如何从泛型类型参数获得‘ . class’属性?

公认的 这个问题答案描述了如何在 Generic<T>类中创建 T的实例。这涉及到将一个 Class<T>参数传递给 Generic构造函数,并从该构造函数调用 newInstance方法。

然后创建一个新的 Generic<Bar>实例,并传入参数 Bar.class

如果新的 Generic类的泛型类型参数不是像 Bar这样的已知类,而是泛型类型参数,那么应该怎么办?假设我有一些其他的类 Skeet<J>,并且我想要从这个类中创建一个新的 Generic<J>实例。然后,如果我尝试传入 J.class,我会得到下面的编译器错误:

cannot select from a type variable.

还有别的办法吗?

触发这个错误的特定代码位是:

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();
/* ... */
}
/* ... */
}
/* ... */
}

错误发生了,因为我不能写 W.class。是否有其他传递相同信息的方法?

31402 次浏览

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);
}

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.

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);