如何使用类标记

时间:2016-05-14 19:37:39

标签: java generics type-erasure nested-generics

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)也不编译。什么是解决这个问题的最佳方法?

2 个答案:

答案 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;
    }
}

如果您需要用于创建/返回列表的特殊代码,您可以考虑的其他内容是tProp的类型获取器:

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

  1. T现在是集合中元素的类型
  2. J现在是Collection类型
  3. 代码

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