2008-10-02 189 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>隱藏了一個真正的問題。