2008-10-02 190 views
19

我有下面的代码不会编译,虽然有一种方法可以使它编译我想了解它为什么不编译。有人能给我启发,特别是为什么我会收到我最后会发布的错误信息吗?类泛型的类型不匹配

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.classClass<T>这个编译与Unchecked cast警告和运行完美。

回答

22

的原因是的Test.class是Type类<测试>的。您不能将类型为<测试>的参考分配给类型为<T>的变量,因为它们不是同一件事。然而,这作品:

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

通配符同时允许类<牛逼>和类<测试>引用被分配到testType。

关于Java泛型行为有很多关于Angelika Langer Java Generics FAQ的信息。我将根据那些使用Number类的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)时,它基本上用Integer代替T

通配符添加额外的灵活性,因为下面将编译:

Class<? extends Number> wildcard = numberClass; 

Class<? extends Number>由于表示的任何类型的一个或NumberNumber一个子类,这是完全合法的,并且在许多情况下可能是有用的。

+0

我想通过参考类型Class和Class类型的变量来了解您的意思。你在谈论有引用的Java,它与它有什么关系? – 2008-10-02 22:27:32

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; 
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>隐藏了一个真正的问题。