2016-04-07 55 views
0

考慮下面的代碼:爲什麼超類通用型不擦除/鑄造

class A<T>{ 
T t; 

public T getValue(){ 
    return t; 
} 

class B<S extends Number> extends A<String>{ 

//some code here.. 
} 

B b = new B<Integer>(); 
String name = b.getValue() // This throws compilation error 

而以下工作:

B<Integer> b = new B<Integer>(); 
String name = b.getValue() // This works...! 

所以我的問題是:

  1. 我是否必須聲明所有涉及的泛型類型? (即使A類的通用類型在B類中聲明)

  2. 或者,我是否缺少基本的東西?

+2

你忽視了關鍵的部分,它是)B.getValue的'的聲明('。 –

+0

之間,爲什麼我應該重寫B中的方法,當我不想更改getValue()的任何行爲?此外,A的類型已被聲明爲B中的Long,以將其刪除。 –

+0

@JimGarrison但'getValue'的縮寫在類'A' – SomeJavaGuy

回答

3

參見JLS 4.8 Raw Types

原始類型被定義爲[...]是通過取一個通用類型聲明的名稱不具有伴隨的類型參數列表形成的引用類型。

原始類型的超類(分別爲超接口)是其任何參數化調用的超類(超接口)的擦除。

換句話說,當你使用B沒有<>,就變成了原始類型,基本上消除所有仿製藥,一路向上的所有基類和接口,即是變得好像AB間沒有」牛逼通用:

class A { 
    Object t; 
    public Object getValue() { 
     return t; 
    } 
} 

class B extends A { 
    //some code here.. 
} 

,這就是爲什麼String name = b.getValue()失敗,因爲getValue()現在返回一個Object


注意在JLS的評論:

使用原始類型只允許作爲讓步的遺留代碼的兼容性。 使用原始類型在將泛型引入到Java編程語言之後編寫的代碼中強烈建議不要使用。未來版本的Java編程語言可能會禁止使用原始類型。

總之,不要。修復你的代碼不要使用原始類型。

但是,您可以縮短右側如下:

B<Integer> b = new B<>(); 
-1

類B的通用值簡單地具有與來自A(龍)的類A.

該方法T的getValue()中的一個)不鏈接將是長的getValue(,不考慮任何泛型在包裝類。

如果你想要一個整數的getValue(),然後簡單地去

class B extends A<Integer> {} 

編輯:你改變你的問題,讓改變響應:)

B被認爲是B(S伸展號碼, T)(因爲它擴展了A)。 如果將一個變量作爲原始類型B存儲,則即使正確聲明,它也是隱式地B(Object,Object)。

與列表中進行測試

List l = new ArrayList<String>(); 
String s = l.get(0); 

您將看到同樣的問題結束。

+0

我編輯過這個問題,因爲前面的問題引起了Number和Long之間的混淆,現在更好地理解我的意思了。 –

+0

我認爲OP寧願想知道,儘管泛型'S'與類'A'無關,而'getValue'由於類'B'的刪減已經返回'Long',爲什麼他必須在定義變量時提供泛型'S',以便'B'爲'A#getValue'返回'Long',而沒有它將返回一個'Object'。 – SomeJavaGuy