Java中用于解决类型擦除的标准方法是将类标记传递给构造函数。例如,我们可以像这样定义一个通用的属性类:
class Prop<T> {
public Prop(Class<T> type) {
this.type = type;
}
Class<T> type;
T t;
}
class IntProp extends Prop<Integer> {
public IntProp() {
super(Integer.class);
}
}
但是如果我现在想要使用另一个泛型类型参数(例如列表)并保留其泛型类型该怎么办呢。我本来希望这样做:
class ListProp<J> extends Prop<ArrayList<J>> {
Class<J> subtype;
public ListProp(Class<J> type) {
super(ArrayList<J>.class);
subtype = type;
}
}
class IntListProp extends ListProp<Integer> {
public IntListProp() {
super(Integer.class);
}
}
但当然super(ArrayList<J>.class)
不编译,super(ArrayList.class)
也不编译。什么是解决这个问题的最佳方法?
答案 0 :(得分:1)
你需要让你的ListProp
类编译的泛型功夫是这一行:
super((Class<List<T>>)(Class<?>)List.class); // compiles
尝试直接从List.class
投射到Class<List<T>>
:
super((Class<List<T>>)List.class); //compile error
导致编译错误:
不可转换的类型;无法将'java.lang.Class'强制转换为'java.lang.Class&gt;
但是,如果您首先转换为类型化的类Class<?>
,尽管是未知类型,您可以然后将其转换为所需的类型类。
然后是完整的可编辑ListProp
课程。
class ListProp<T> extends Prop<List<T>> {
Class<T> subtype;
public ListProp(Class<T> type) {
super((Class<List<T>>)(Class<?>)List.class); // magic double cast
subtype = type;
}
}
如果您需要用于创建/返回列表的特殊代码,您可以考虑的其他内容是t
上Prop
的类型获取器:
public T getT() {
return t;
}
然后您可以在ListProp
中协变覆盖以返回List<T>
@Override
public List<T> getT() {
return Arrays.asList(subtype.newInstance()); // or whatever
}
应该注意的是,如果您的实现使用了类,那么您只需要类令牌,这在您的示例代码中未显示。如果你实际上没有使用类令牌,你可以让类型推断为你做输入。
答案 1 :(得分:0)
我知道一种可以解决问题的方法。类型擦除用于在编译后擦除类型,因为它们不需要运行。这可能就是为什么你不能只使用类型访问类List。 List本身使用泛型,因此为它提供一个类没有意义或可能,因为在你的情况下T实际上是列表元素的类型。该类实际上是ArrayList。您正在寻找的是您正在使用的集合类型以及您正在使用的元素类型。我已经改变了你的代码,以便你可以接受两种类型的构造函数。
class ListProp<T, J> extends Prop<T, J> {
Class<T> subtype;
Class<J> subtypeElementList:
public ListProp(Class<T> typeElement, Class<J> typeList) {
super(typeElement, typeList);
subtype = typeElement;
subtypeElementList = typeList;
}
}
class IntListProp extends ListProp<Integer, ArrayList> {
public IntListProp() {
super(Integer.class, ArrayList.class);
}
}
class Prop<T, J> {
// TODO: Maybe here the elements again? Depends on what you want to do...
//
// or maybe just use the integer as you had previously.
public Prop(Class<T> integerClass, Class<J> arrayListClass) {
}
}