2015-03-02 42 views
19

我正在使用Android Studio 1.1.0。未檢查的分配警告

這將導致沒有任何警告:

public static class A { 
    public Map<Integer, String> getMap() { 
     return null; 
    } 
} 

public static class B { 
    public void processA(A a) { 
     Map<Integer, String> map = a.getMap(); 
    } 
} 

但要A通用:

public static class A<T> { 
    public Map<Integer, String> getMap() { 
     return null; 
    } 
} 

這行:

Map<Integer, String> map = a.getMap(); 

現在讓你一個警告:"Unchecked assignment: 'java.util.Map to java.util.Map<java.lang.Integer, java.lang.String>'

儘管getMap的簽名完全獨立於T,並且該代碼對於包含Map的類型是明確的。

我知道我可以通過重新實現processA如下襬脫了警告:

public <T> void processA(A<T> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

但我幹嘛要這麼做? T這裏有什麼關係?

所以,問題是 - 爲什麼類型擦除得不僅影響T(這是可以理解的 - 如果我傳遞的A一個實例,T是未知的),而且還「硬編碼」像<Integer, String>一般簽名在這種情況下?

回答

13

在你的第二個情況下,當你這樣做:

public void processA(A a) 

你說的A是什麼意思?這是否意味着A<String>A<List<String>>還是什麼?你可能沒有使用任何與A類型相關的東西,但是嘿編譯器不知道這個事實。編譯器,只是A是恐慌的標誌。

在你的情況,因爲你不特別需要知道的類型,你可以:

public void processA(A<?> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

具有A<?>方法的參數類型,你不特別關心的A類型僅僅指定一張通配符。對你而言意味着:A的任何對象都可以作爲其泛型類型。實際上,這意味着你不知道類型。它無用,因爲你不能以類型安全的方式做任何與A有關的事情,因爲?幾乎可以成爲任何東西!

但按你的方法體,它使世界上所有的有意義的使用A<?>因爲在身體任何地方你的實際需要'你可能沒有使用與A型的東西的A

+0

類型,但是嘿編譯器不知道這個事實 - 好吧,它可以很容易地知道它,只要看一下'processA'的實現,不難驗證'T'是不相關的; )按照你的建議,我會用''去,但是我對編譯器感到失望。 – 2015-03-02 12:10:36

+0

@KonradMorawski在理想的世界裏,只有'A'應該是非法的,代碼不應該被編譯。但是出於向後兼容的原因,這是允許的。對於聲明爲「A 」的類,其泛型類型對於執行與「A」相關的任何操作都非常重要。因此,不應該允許使用'A'(實際上在Scala中,僅僅使用'A'是非法的) – Jatin 2015-03-02 12:17:21

+0

是的,我想......我不使用Scala,但是我來自C#端的世界和Java的泛型感覺就像穿着太小的鞋子一樣。 – 2015-03-02 12:23:10

5

當你的意思是接受任何可能的類型TA<T>,但不需要T,這是正確使用通配符和寫作A<?>表示。這樣做將擺脫警告在代碼:

public void processA(A<?> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

使用裸型A不等同對待。正如在Java Language Specification說明的,原始類型,如不打算在新代碼中使用:

未經檢查的轉換用於啓用的傳統代碼的平滑互操作,引入一般類型的之前寫入,與庫,已經經歷了轉換,以使用通用性(我們稱之爲「基因化」的過程)。在這種情況下(最着名的是java.util中Collections Framework的客戶端),傳統代碼使用原始類型(例如Collection而不是Collection <String>)。原始類型的表達式作爲參數傳遞給庫方法,這些方法使用這些相同類型的參數化版本作爲其相應形式參數的類型。

在使用泛型的類型系統下,此類調用不能顯示爲靜態安全。拒絕這種調用會使大量現有代碼無效,並阻止它們使用較新版本的庫。這反過來會阻止圖書館供應商利用通用性。爲了防止這種不受歡迎的事件發生,可以將原始類型轉換爲對原始類型引用的泛型類型聲明的任意調用。雖然轉換不健全,但作爲實用性的讓步是可以容忍的。在這種情況下發出未經檢查的警告。