如何使用 class 标记保留嵌套泛型的泛型类型
How to keep generic type of nested generics with class tokens
Java 中解决类型擦除的标准方法是将 class 标记传递给构造函数。例如,我们可以像这样定义一个通用的 属性 class:
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)
也不编译。解决此问题的最佳方法是什么?
小介绍
我知道一种解决问题的方法。类型擦除用于在编译后擦除类型,因为 运行 不需要它们。这可能就是为什么您不能只使用类型访问 class 列表的原因。 List 本身使用泛型,因此为此提供 class 没有意义或不可能,因为在您的情况下 T 实际上是列表元素的类型。 class 实际上是ArrayList。您正在寻找的是您正在使用的集合类型和您正在使用的元素类型。我已经稍微更改了您的代码,以便您可以接受两种类型的构造函数。
- T 现在是集合中元素的类型
- J 现在是集合类型
代码
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) {
}
}
编译 ListProp
class 所需的泛型功夫是这一行:
super((Class<List<T>>)(Class<?>)List.class); // compiles
正在尝试直接从 List.class
转换为 Class<List<T>>
:
super((Class<List<T>>)List.class); //compile error
导致编译错误:
Inconvertible types; cannot cast 'java.lang.Class' to 'java.lang.Class>
但是如果你先转换为类型class Class<?>
,尽管类型未知,你可以然后将其转换为所需的类型 class.
完整的可编译ListProp
class就是这样了。
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;
}
}
如果您需要 creating/returning 列表的特殊代码,您可能会考虑的其他内容是 Prop
上 t
的类型 getter:
public T getT() {
return t;
}
然后您可以在 ListProp
中协变地覆盖 return a List<T>
@Override
public List<T> getT() {
return Arrays.asList(subtype.newInstance()); // or whatever
}
请注意,如果您的实现使用 class,您只需要 class 标记,您的示例代码中没有显示。如果您实际上并不使用 class 标记,则可以让类型推断为您完成输入。
Java 中解决类型擦除的标准方法是将 class 标记传递给构造函数。例如,我们可以像这样定义一个通用的 属性 class:
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)
也不编译。解决此问题的最佳方法是什么?
小介绍
我知道一种解决问题的方法。类型擦除用于在编译后擦除类型,因为 运行 不需要它们。这可能就是为什么您不能只使用类型访问 class 列表的原因。 List 本身使用泛型,因此为此提供 class 没有意义或不可能,因为在您的情况下 T 实际上是列表元素的类型。 class 实际上是ArrayList。您正在寻找的是您正在使用的集合类型和您正在使用的元素类型。我已经稍微更改了您的代码,以便您可以接受两种类型的构造函数。
- T 现在是集合中元素的类型
- J 现在是集合类型
代码
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) {
}
}
编译 ListProp
class 所需的泛型功夫是这一行:
super((Class<List<T>>)(Class<?>)List.class); // compiles
正在尝试直接从 List.class
转换为 Class<List<T>>
:
super((Class<List<T>>)List.class); //compile error
导致编译错误:
Inconvertible types; cannot cast 'java.lang.Class' to 'java.lang.Class>
但是如果你先转换为类型class Class<?>
,尽管类型未知,你可以然后将其转换为所需的类型 class.
完整的可编译ListProp
class就是这样了。
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;
}
}
如果您需要 creating/returning 列表的特殊代码,您可能会考虑的其他内容是 Prop
上 t
的类型 getter:
public T getT() {
return t;
}
然后您可以在 ListProp
中协变地覆盖 return a List<T>
@Override
public List<T> getT() {
return Arrays.asList(subtype.newInstance()); // or whatever
}
请注意,如果您的实现使用 class,您只需要 class 标记,您的示例代码中没有显示。如果您实际上并不使用 class 标记,则可以让类型推断为您完成输入。