Class Generics的类型不匹配

时间:2008-10-02 16:44:56

标签: java generics

我有以下不能编译的代码,虽然有一种方法可以使它编译,我想了解它为什么不编译。有人可以告诉我具体为什么我会收到我将在最后发布的错误消息吗?

public class Test {
    public static void main(String args[]) {
        Test t = new Test();
        t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
        Class<T> testType = type == null ? Test.class : type; //Error here
        System.out.println(testType);
    }
}

Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>

通过将Test.class投射到Class<T>,可以使用Unchecked cast警告进行编译并完美运行。

3 个答案:

答案 0 :(得分:23)

原因是Test.class属于Class&lt; Test&gt;类型。您不能分配Class&lt; Test&gt;类型的引用到类&lt; T&gt;类型的变量因为它们不是一回事。然而,这有效:

Class<? extends Test> testType = type == null ? Test.class : type;

通配符允许Class&lt; T&gt;和类&lt;测试&gt;引用分配给testType。

Angelika Langer Java Generics FAQ有大量有关Java泛型行为的信息。我将根据那些使用Number类heirarchy Java的核心API的信息提供一个示例。

考虑以下方法:

public <T extends Number> void testNumber(final Class<T> type)

这是为了允许以下语句成功编译:

testNumber(Integer.class);
testNumber(Number.class);

但以下内容无法编译:

testNumber(String.class);

现在考虑以下陈述:

Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;

第二行无法编译并产生此错误Type mismatch: cannot convert from Class<Number> to Class<Integer>。但是Integer扩展了Number,那为什么会失败呢?看看接下来的两个陈述,看看为什么:

Number anumber = new Long(0);
Integer another = anumber;

很容易理解第二行为什么不在这里编译。您无法将Number的实例分配给类型为Integer的变量,因为无法保证Number实例属于兼容类型。在此示例中,Number实际上是Long,当然无法将其分配给Integer。实际上,错误也是类型不匹配:Type mismatch: cannot convert from Number to Integer

规则是不能将实例分配给作为实例类型的子类的变量,因为不能保证它是兼容的。

泛型以类似的方式表现。在泛型方法签名中,T只是一个占位符,用于指示方法允许编译器的内容。当编译器遇到testNumber(Integer.class)时,它基本上用T替换Integer

通配符增加了额外的灵活性,如下所示:

Class<? extends Number> wildcard = numberClass;

由于Class<? extends Number>表示Number的任何类型或Number的子类,因此这在任何情况下都是完全合法且可能有用。

答案 1 :(得分:4)

假设我扩展了测试:

public class SubTest extends Test {
  public static void main(String args[]) {
    Test t = new Test();
    t.testT(new SubTest());
  }
}

现在,当我调用testT时,类型参数<T>SubTest,这意味着变量testTypeClass<SubTest>Test.class类型为Class<Test>,不能分配给Class<SubTest>类型的变量。

将变量testType声明为Class<? extends Test>是正确的解决方案;施放到Class<T>隐藏着一个真正的问题。

答案 2 :(得分:1)

删除条件,错误更好......

public class Test {
    public static void main(String args[]) {
        Test t = new Test();
        t.testT(null);
    }

    public <T extends Test> void testT(Class<T> type) {
    Class<T> testClass = Test.class;
        System.out.println(testClass);
    }
}


Test.java:10: incompatible types
found   : java.lang.Class<Test>
required: java.lang.Class<T>
        Class<T> testClass = Test.class;