2014-08-27 73 views
3

我有這本書的代碼在Java思考,其中布魯斯表示調用方法設置()的警告。代碼如下:
通用類型擦除警告

package testPackage; 

    class GenericBase<T> { 
    private T element; 
    public void set(T arg) { arg = element; } 
    public T get() { return element; } 
    } 
    class Derived1<T> extends GenericBase<T> {} 
    class Derived2 extends GenericBase {} // No warning 
    // class Derived3 extends GenericBase<?> {} 
    // Strange error: 
    // unexpected type found : ? 
    // required: class or interface without bounds 
    public class ErasureAndInheritance { 
    @SuppressWarnings("unchecked") 
    public static void main(String[] args) { 
     Derived2 d2 = new Derived2(); 
     Object obj = d2.get(); 
     d2.set(obj); // Warning here! 
     } 
    } 

如果我刪除了註釋,我得到以下警告:
類型安全:該方法集(對象)屬於原始類型GenericBase。參考泛型GenericBase應參數化

我的問題是,爲什麼在set()方法上顯示警告?有人可以解釋這個警告的含義嗎?
順便說一句,我對Java泛型是全新的,雖然我讀了其他關於泛型的問題,但我仍然對Erasure感到困惑。

+0

Erasure =>在編譯過程之後,代碼不知道有關泛型的任何信息 – 2014-08-27 14:39:15

+0

@MarcoAcierno那麼,我明白,但我的混淆來自混合原始和參數化類型。 – 2014-08-27 14:41:55

回答

3

從Java文檔here

泛型被引入Java語言在編譯時提供的緊縮式 檢查,並支持泛型編程。爲了 實現泛型,Java編譯器適用類型擦除到:

  • 在泛型類型與他們的界限更換所有類型的參數或對象,如果類型參數是無限的。因此,產生的字節碼 僅包含普通的類,接口和方法。
  • 如果需要,插入類型可以保護類型安全。
  • 生成橋接方法以保留擴展泛型中的多態性。
  • 類型擦除確保不爲參數化類型創建新類;因此,泛型不會導致運行時開銷。

簡單:每一個通用的編譯過程後Object,它只是增加了鑄件的你,如果你做錯了什麼就會產生一個編譯器錯誤。

關於unchecked註解,它使用時,編譯器不能確保你在做什麼是正確的(事實上,你使用原始類型,是同樣的事情GenericBase<Object>

你有自set方法以來的警告(T類型除外),但由於您使用的是原始類型,因此它不知道T是什麼,並生成此警告讓您知道您正在使用原始類型(壞東西)。

您可以使用註釋來說:「我知道這是一種原始類型,但我知道這是合法的,我知道我在做什麼」。

混合原料類型和一般類型可能是由於泛型被實現,正如我上面所說的方式,T變得Object它意味着像GenericBase原始目的是像GenericBase<T>同樣的事情,編譯器處理之後。

之所以沒有要求使用泛型進行任何類型的鑄造,是因爲它會爲您添加鑄件(並且您可以確保代碼始終在運行時工作,而不用擔心可能的ClassCastException)。

+0

我想澄清的一件事是,當你在最後一段關於自動鑄造的說法中說,你的意思是沒有得到get()方法的警告(因爲返回T)的原因是自動處理鑄造在這種情況下? – 2014-08-27 14:54:31

+0

在這種情況下,您沒有警告,因爲Derived2包含對象,並將其保存在對象中。因此,沒有理由產生警告,因爲根本不需要投射 – 2014-08-27 14:58:54

+0

如果我考慮你的推理,那麼在set()中,接收參數也將被轉換爲Object類型,爲什麼警告出現呢?你知道,在調用set()時正在傳遞一個對象)我的意思是類型標識符T會在T存在的情況下被轉換爲Object嗎? – 2014-08-27 15:11:45