ChatGPT解决这个技术问题 Extra ChatGPT

How do I get the `.class` attribute from a generic type parameter?

The accepted answer to this question describes how to create an instance of T in the Generic<T> class. This involves passing in a Class<T> parameter to the Generic constructor and callin the newInstance method from that.

A new instance of Generic<Bar> is then created, and the parameter Bar.class is passed in.

What do you do if the generic type parameter for the new Generic class is not some known class like Bar but is itself a generic type parameter? Suppose I had some other class Skeet<J> and I wanted to create a new instance of Generic<J> from inside that class. Then, if I try to pass in J.class I get the following compiler error:

cannot select from a type variable.

Is there any way around this?

The specific bit of code triggering the error for me is:

public class InputField<W extends Component & WidgetInterface>
                                                 extends InputFieldArray<W>
{
  public InputField(String labelText)
  {
    super(new String[] {labelText}, W.class);
  }
  /* ... */
}

public class InputFieldArray<W extends Component & WidgetInterface>
                                                                 extends JPanel
{
   /* ... */
  public InputFieldArray(String[] labelText, Class<W> clazz)
                          throws InstantiationException, IllegalAccessException
  {
    /* ... */

    for (int i = 0 ; i < labelText.length ; i++) {
      newLabel = new JLabel(labelText[i]);
      newWidget = clazz.newInstance();
      /* ... */
    }
    /* ... */
  }
  /* ... */
}

The error happens, because I can't write W.class. Is there some other way of passing in the same information?

Your question maybe more clear if you post a code example (i.e. the one that triggers the compiler error).
But you must be having the class name in Skeet<J> right? You need to pass that class to the Generic constructor. If you show actual code, we can help you better.
you can't use J.class because of type erasure. But you can get concrete Class variable on Skeet<J> construction
On the linked question, Jon didn't literally mean T.class - you can't use .class on type parameters. He meant a Class<T> would need to be passed in by the caller.
I know. I, however, would like to be able to pass in the class of J. Is that possible?

P
Paul Bellora

Using .class on a type parameter isn't allowed - because of type erasure, W will have been erased to Component at runtime. InputField will need to also take a Class<W> from the caller, like InputFieldArray:

public InputField(String labelText, Class<W> clazz)
{
    super(new String[] {labelText}, clazz);
}

Base on the given type erasure link, the generic type will be replaced by type Object since no bound is given in this case. So because type Class is the subclass of Object, I think in this case we won't be able to call .class. But what if the given bound is not Object (like <? extends Foo>, I mean the method .class should still be selectable in this case. I'm a little bit confused here. @Paul Bellora
@Dreamer .class isn't a method or anything that can be dynamically resolved at runtime. It's a compile-time construct used to statically get the Class object representing an explicit concrete type.
M
Mark Rotteveel

If you're using the Gson library, you can get the type of T easily by using TypeToken. The class documentation is available here:

I did it like this:

This is my class definition:

public class ManagerGeneric <T> {}

This is in my method:

// Get the type of generic parameter
Type typeOfT = new TypeToken<T>(){}.getType();
// Deserialize
T data = gson.fromJson(json, typeOfT);

n
nanofarad

W may not be available due to type erasure. You should require that a Class<W> is passed into the method. You get a class object and its generic ensures that only W and no subclass is passed in, due to covariance.

public InputField(String labelText, Class<W> cls)
{
    super(new String[] {labelText}, cls);
}

will take W.class but not WSubtype.class.