为什么Class <t extends =“” base =“”>不适用于Class <base />?

时间:2018-09-11 00:36:42

标签: java generics

我正在创建一个小型应用程序,偶然发现了以下问题。

我的应用程序中有一个collections.Counter,签名为List<Class<MyCustomBaseClass>>的函数。
public <T extends MyCustomBaseClass> void addClass(Class<T> clazz)应该将AddClass放入列表中。但是我在那里遇到以下错误:

  

clazz

这是我可以简化的3个班级:

The method add(Class<MyCustomBaseClass>) in the type List<Class<MyCustomBaseClass>> is not applicable for the arguments (Class<T>)

// Program.java
package me.mischa.stackoverflow;

import java.util.ArrayList;
import java.util.List;

public class Program {

    private List<Class<MyCustomBaseClass>> _listOfClasses;
    private static Program _instance;

    public Program() {
        _listOfClasses = new ArrayList<>();
    }

    public static void main(String[] args) {
        Program program = new Program();
        program.addClass(MyCustomChildClass.class);
    }

    public <T extends MyCustomBaseClass> void addClass(Class<T> clazz) {
        _listOfClasses.add(clazz);
    }

}

// MyCustomBaseClass.java
package me.mischa.stackoverflow;

public class MyCustomBaseClass {

}

错误在第// MyCustomChildClass.java package me.mischa.stackoverflow; public class MyCustomChildClass extends MyCustomBaseClass { }

我不明白为什么_listOfClasses.add(clazz);<T extends MyCustomBaseClass>不兼容

2 个答案:

答案 0 :(得分:2)

Java的泛型是不变的。这意味着,作为类型参数的Class<MyCustomBaseClass>完全意味着,不允许表示MyCustomBaseClass子类的Class对象。

在您的addClass方法中,您仅在定义T时给出了上限– T可以是MyCustomBaseClass的子类,例如您的班级MyCustomChildClass。由于不匹配,编译器不允许此调用。

您可以通过提供匹配的上限来扩展_listOfClasses中的允许范围,这将允许方法addClass进行编译。

private List<Class<? extends MyCustomBaseClass>> _listOfClasses;

顺便说一句,由于TaddClass的类型实际上并不重要,因此您可以删除它并使用通配符。

public void addClass(Class<? extends MyCustomBaseClass> clazz) {

答案 1 :(得分:0)

Java的泛型是不变的。这是有原因的。想象以下代码(注意:showExpr :: Expr -> Expr showExpr (Node op (SomeOperand a) (SomeOperand b)) = showOperand a ++ show op ++ showOperand b showExpr (Value i) = show i NumberInteger的超类型):

Double

在上面的 if 中,如果它已经是有效的Java,则您正在将Integer分配给Double,这是一个问题,因为Integer不是Double。这就是为什么实际上,如果您尝试编译以上内容,将无法正常工作。第二行被标记为无效的Java,因为无法将List<Double> doublesOnly = new ArrayList<Double>(); List<Number> numbers = doublesOnly; numbers.add(new Integer(5)); Double d = doublesOnly.get(0); 分配给List<Double>。有一个解决方案:

List<Number>

这次,第3行出现错误:除了List<Double> doublesOnly = new ArrayList<Double>(); List<? extends Number> numbers = doublesOnly; numbers.add(new Integer(5)); Double d = doublesOnly.get(0); 之外,您无法向List<? extends Something>添加任何内容。无法修复此代码,这很好,因为我们从根本上做不好的事情。

针对您的具体情况,解决方案有两个方面:

  1. 通常,您应该避免在API中使用null的概念。通常,使用工厂代替。

  2. 如果必须的话,请尝试以下操作:Class<?>。是的,扩展了2个。您可以将List<Class<? extends MyCustomBaseClass>>添加到此列表。