如何使用 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。您正在寻找的是您正在使用的集合类型和您正在使用的元素类型。我已经稍微更改了您的代码,以便您可以接受两种类型的构造函数。


  1. T 现在是集合中元素的类型
  2. 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.

完整的可编译ListPropclass就是这样了。

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 列表的特殊代码,您可能会考虑的其他内容是 Propt 的类型 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 标记,则可以让类型推断为您完成输入。