6

我在使用类型参数初始化类时遇到问题。这似乎是 Java 类型推断的一个缺点,我想知道是否有解决方法或更好的方法来实现这一点。

public class ParentModel {}

public class ChildModel extends ParentModel {}

public class Service<E extends ParentModel, T extends Collection<E>> {
    private Class<T> classOfT;
    private Class<E> classOfE;

    public Service(Class<E> classOfE, Class<T> classOfT) {
        this.classOfE = classOfE;
        this.classOfT = classOfT;
    }
}

public class BusinessLogic {
    public void someLogic() {
        Service<ChildModel, ArrayList<ChildModel>> service = new 
            Service<ChildModel, ArrayList<ChildModel>>(ChildModel.class, ArrayList.class);
    }
}

编译时错误在BusinessLogic::someLogic()

构造函数 Service<ChildModel, ArrayList<ChildModel>>(Class<ChildModel>, Class<ArrayList>) 未定义

编译为 Java 7。

4

2 回答 2

2

因为 Java 中的泛型是“通过擦除”实现的,所以没有Class<ArrayList<ChildModel>>>,只有Class<ArrayList>.

您可以做的是允许超类型。

Class<? super T> classOfT;
Class<? super E> classOfE;
public Service(Class<? super E> classOfE, Class<? super T> classOfT) {

或者,您可以对课程进行双重转换:

Class<ArrayList<Integer>> clazz =
    (Class<ArrayList<Integer>>) (Class<? super ArrayList>) 
    ArrayList.class;

但请注意:该类只是ArrayList- Java 不会在运行时对泛型执行额外的类型检查。你自己看:

ArrayList<Integer> a1 = new ArrayList<>();
ArrayList<Double> a2 = new ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());

同一个班级。在运行时,泛型几乎消失了

于 2016-03-14T01:31:57.127 回答
1

因为没有ArrayList<ChildModel>.class什么优雅的方法可以解决这个问题。正如 Yassin 所提到的,您可以将原始类型传递给您的构造函数,如下所示:

Service<ChildModel, ArrayList<ChildModel>> s1 = 
        new Service<>(ChildModel.class, (Class) ArrayList.class) 

您调用的不同之处在于,这里我们使用的是 raw type Class,而在您的示例中使用的是类型Class<ArrayList>(所以这不是错误)。

另一种选择是从实际实例中获取类型:

Class<ArrayList<ChildModel>> fromObj = 
        (Class<ArrayList<ChildModel>>) new ArrayList<ChildModel>(0).getClass();

这更冗长,但我更喜欢原始类型(在这两种情况下,您都会收到编译器警告)

于 2016-03-13T22:45:32.820 回答