天天看點

當泛型遇到重載

當泛型遇到了重載,好戲,就發生了。

請看下面代碼:

當泛型遇到重載

問題:代碼能正确編譯嗎?

這個題目是一個考察泛型的題目。java裡面,泛型實際上是“僞泛型”,并不像C#那樣是實際上的泛型。

IDE會提示我們下面的錯誤:

Method test(List<String>) has the same erasure test(List<E>) as another method in type TR

在java中,泛型隻存在于源代碼之中,在編譯過後的代碼中,泛型資訊已經被“擦除”了。上面的代碼被編譯之後的樣子應該是下面類似的代碼:

當泛型遇到重載

兩個函數具有相同的簽名,當然編譯器會拒絕為我們編譯這樣的代碼。

在java這種僞泛型中,List<String>和List<Integer>,編譯之後,是相同的類型。

但是在c#這種真實泛型中,上面兩個就是不同的類型了。

故事到這裡就結束了嗎??顯然沒有

------------------------------------昏昏咯咯-------------------------------------

看下面代碼:

當泛型遇到重載

問,這段代碼能正常編譯嗎?

熟悉class檔案結構的人能知道,這段代碼能正常編譯(重載成功了!)。而且還能正常執行呢!!!

當泛型遇到重載

代碼輸出:

integer

string

疑問來了。jvm規定,函數的傳回值并不參與“函數簽名”的生成,那麼僅僅改變了函數傳回值,進而讓不能編譯的代碼通過了編譯并且能正常執行了,這不是很沖突嗎?

原因在于,雖然函數的傳回值不參與函數簽名的生成,但是在class檔案中,隻要描述符不完全一緻的兩個方法就能共存于一個class檔案中。

【java代碼中,函數的特征簽名僅僅包括方法名稱、參數類型以及參數順序。但在位元組碼中,特征簽名還包括了方法的傳回值以及受查異常表,這就是為什麼在class檔案中,其他都相同僅僅傳回值不同的兩個方法能共存的原因】