日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java泛型——桥方法

發布時間:2023/12/3 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java泛型——桥方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【0】README

0.1)以下內容轉自: http://www.cnblogs.com/ggjucheng/p/3352519.html


【1】泛型約束和局限性—— 類型擦除所帶來的麻煩

1.1)繼承泛型類型的多態麻煩。(—— 子類沒有覆蓋住父類的方法 )

  • 看看下面這個類SonPair
class SonPair extends Pair<String>{ public void setFirst(String fir){....} }
  • 很明顯,程序員的本意是想在SonPair類中覆蓋父類Pair的setFirst(T fir)這個方法。但事實上,SonPair中的setFirst(String fir)方法根本沒有覆蓋住Pair中的這個方法。
  • 原因很簡單,Pair在編譯階段已經被類型擦除為Pair了,它的setFirst方法變成了setFirst(Object fir)。 那么SonPair中setFirst(String)當然無法覆蓋住父類的setFirst(Object)了。
    這對于多態來說確實是個不小的麻煩,我們看看編譯器是如何解決這個問題的。
  • 編譯器 會自動在 SonPair中生成一個橋方法(bridge method ) :
public void setFirst(Object fir) {setFirst((String) fir) }
  • 這樣,SonPair的橋方法確實能夠覆蓋泛型父類的setFirst(Object) 了。而且橋方法內部其實調用的是子類字節setFirst(String)方法。對于多態來說就沒問題了。

1.2)問題還沒有完,多態中的方法覆蓋是可以了,但是橋方法卻帶來了一個疑問:

  • 現在,假設 我們還想在 SonPair 中覆蓋getFirst()方法呢?
class SonPair extends Pair<String> {public String getFirst(){....} }
  • 由于需要橋方法來覆蓋父類中的getFirst,編譯器會自動在SonPair中生成一個 public Object getFirst()橋方法。 (干貨——引入了橋方法,該方法是編譯器生成的,不是程序員碼出來的)
  • 但是,疑問來了,SonPair中出現了兩個方法簽名一樣的方法(只是返回類型不同):
    • ①String getFirst() // 自己定義的方法
    • ②Object getFirst() // 編譯器生成的橋方法
  • 難道,編譯器允許出現方法簽名相同的多個方法存在于一個類中嗎?事實上有一個知識點可能大家都不知道:
    • ① 方法簽名 確實只有方法名+參數列表 。這毫無疑問!
    • ② 我們絕對不能編寫出方法簽名一樣的多個方法 。如果這樣寫程序,編譯器是不會放過的。這也毫無疑問!
    • ③ 最重要的一點是: JVM會用參數類型和返回類型來確定一個方法。 一旦編譯器通某種方式自己編譯出方法簽名一樣的兩個方法 (只能編譯器自己來創造這種奇跡,我們程序員卻不能人為的編寫這種代碼)。JVM還是能夠分清楚這些方法的,前提是需要返回類型不一樣。

1.3) 泛型類型中的方法沖突

//在上面代碼中加入equals方法 public class Pair<T>{ public boolean equals(T value){ return (first.equals(value)); } }
  • 這樣看似乎沒有問題的代碼連編譯器都通過不了:
  • 【Error】 Name clash(命名沖突): The method equals(T) of type Pair has the same erasure as equals(Object) of type Object but does not override it。

編譯器說你的方法與Object中的方法沖突了。這是為什么?

  • 開始我也不太明白這個問題,覺得好像編譯器幫助我們使得equals(T)這樣的方法覆蓋上了Object中的equals(Object)。
  • 經過大家的討論,我覺得應該這么解釋這個問題?
    • 首先、我們都知道子類方法要覆蓋,必須與父類方法具有相同的方法簽名(方法名+參數列表)。而且必須保證子類的訪問權限>=父類的訪問權限。這是大家都知道的事實。
    • 然后、在上面的代碼中,當編譯器看到Pair中的equals(T)方法時,第一反應當然是equals(T)沒有覆蓋住父類Object中的equals(Object)了。
    • 接著、編譯器將泛型代碼中的T用Object替代(擦除)。突然發現擦除以后equals(T)變成了equals(Object),糟糕了,這個方法與Object類中的equals一樣了。
  • 基于開始確定沒有覆蓋這樣一個想法,編譯器徹底的瘋了(精神分裂)。
  • 然后得出兩個結論:①堅持原來的思想:沒有覆蓋。但現在一樣造成了方法沖突了。 ②寫這程序的程序員瘋了(哈哈)。
  • 再說了,拿Pair對象和T對象比較equals,就像牛頭對比馬嘴,哈哈,邏輯上也不通呀。

1.4)沒有泛型數組一說

Pair<String>[] stringPairs=new Pair<String>[10]; Pair<Integer>[] intPairs=new Pair<Integer>[10];
  • 這種寫法編譯器會指定一個Cannot create a generic array of Pair的錯誤
    • 我們說過泛型擦除之后,Pair[]會變成Pair[],進而又可以轉換為Object[];
    • 假設泛型數組存在,那么
Object[0]=stringPairs[0]; Ok Object[1]=intPairs[0]; Ok
  • 這就麻煩了,理論上將Object[]可以存儲所有Pair對象,但這些Pair對象是泛型對象,他們的類型變量都不一樣,那么調用每一個Object[]數組元素的對象方法可能都會得到不同的記過,也許是個字符串,也許是整形,這對于JVM可是無法預料的。
  • 記住: 數組必須牢記它的元素類型,也就是所有的元素對象都必須一個樣,泛型類型恰恰做不到這一點。即使Pair< String>,Pair< Integer>… 都是Pair類型的,但他們還是不一樣。

總結:泛型代碼與JVM

  • 虛擬機中沒有泛型,只有普通類和方法。
  • 在編譯階段,所有泛型類的類型參數都會被Object或者它們的限定邊界來替換。(類型擦除)
  • 在繼承泛型類型的時候,橋方法的合成是為了避免類型變量擦除所帶來的多態災難。

總結

以上是生活随笔為你收集整理的java泛型——桥方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。