Java Bridge Method 詳解

背景: 最近在看Spring Mvc的源碼, 看到調(diào)用請(qǐng)求處理方法的過(guò)程中時(shí)看到最后調(diào)用的請(qǐng)求方法時(shí)拿取的是bridgeMethod, 如下

 // InvocableHandlerMethod#doInvoke(只保留關(guān)鍵代碼)

 protected Object doInvoke(Object... args) throws Exception {
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
       // 這里獲取請(qǐng)求處理方法(也就是我們?cè)赾ontroller中進(jìn)行對(duì)請(qǐng)求進(jìn)行處理的方法)
       return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
     ...
       異常處理代碼
     ...
    }
 }

可以看到spring是從HandlerMethod(請(qǐng)求處理方法類(lèi), 每一個(gè)請(qǐng)求處理方法就是這個(gè)類(lèi)的實(shí)例)中調(diào)用getBridgedMethod拿到真正的請(qǐng)求處理方法而不是通過(guò)getMethod方法獲取, 那getBridgedMethod返回的是什么呢? 看一下HandlerMethodgetBridgedMethod的具體實(shí)現(xiàn)

 /**
  * If the bean method is a bridge method, this method returns the bridged
  * (user-defined) method. Otherwise it returns the same method as {@link #getMethod()}.
  */
 protected Method getBridgedMethod() {
    return this.bridgedMethod;
 }

關(guān)鍵的地方在注釋中說(shuō)明了: 如果請(qǐng)求處理的方法是一個(gè)bridge method那么就返回bridge method, 否則返回值就和getMethod一樣. 那么問(wèn)題就來(lái)了, 什么是bridge method?

1. bridge method

什么是bridge method, 讓我們來(lái)看一下JSL中對(duì)bridge method的定義

jsl_bridge_method

也就是說(shuō)如果一個(gè)類(lèi)繼承了一個(gè)范型類(lèi)或者實(shí)現(xiàn)了一個(gè)范型接口, 那么編譯器在編譯這個(gè)類(lèi)的時(shí)候就會(huì)生成一個(gè)叫做橋接方法的混合方法(混合方法簡(jiǎn)單的說(shuō)就是由編譯器生成的方法, 方法上有synthetic修飾符), 這個(gè)方法用于范型的類(lèi)型安全處理, 用戶(hù)一般不需要關(guān)心橋接方法. 更詳細(xì)的可以看JSL bridge method

2. 更直觀的了解bridge method

// 定義一個(gè)范型接口
public interface Parent<T> {
    T bridgeMethod(T param);
}

// 定義一個(gè)類(lèi)實(shí)現(xiàn)范型接口
public class Child implements Parent<String> {
    public String bridgeMethod(String param) {
        return param;
    }
}

// 測(cè)試方法
public class BridgeMethodTest {
    public static void main(String[] args) throws Exception {
       // 使用java的多態(tài)
        Parent parent = new Child();
        System.out.println(parent.bridgeMethod("abc123"));// 調(diào)用的是實(shí)際的方法
        Class<? extends Parent> clz = parent.getClass();
        Method method = clz.getMethod("bridgeMethod", Object.class); // 獲取橋接方法
        System.out.println(method.isBridge()); // true
        System.out.println(method.invoke(parent, "hello")); // 調(diào)用的是橋接方法
        System.out.println(parent.bridgeMethod(new Object()));// 調(diào)用的是橋接方法, 會(huì)報(bào)ClassCastException: java.lang.Object cannot be cast to java.lang.String`錯(cuò)誤`
    }
}

使用jclasslib工具看一下編譯器為我們生成了什么了

這個(gè)是Parent.class的字節(jié)碼, 可以看到范型T被換成了Object, 所以方法的簽名是
public abstract Object bridgeMethod(Object param)

JSL_BRIDGE_METHOD_1

這個(gè)是Child.class的字節(jié)碼, 可以看到生成了一個(gè)bridgeMethod的方法, 這個(gè)方法的簽名是

public String bridgeMethod(String param)

JSL_BRIDGE_METHOD_2

這個(gè)是Child.class的字節(jié)碼, 可以看到還生成了一個(gè)bridgeMethod的橋接方法, 這個(gè)方法的簽名是

public synthetic bridge Object bridgeMethod(Object param)

JSL_BRIDGE_METHOD_3

注: 也可以使用javap -c -v classFileName.class打印類(lèi)似的信息, 但是使用jclasslib更加直觀方便

3. 編譯器生成bridge method的意義

簡(jiǎn)單來(lái)說(shuō), 編譯器生成bridge method的目的就是為了和jdk1.5之前的字節(jié)碼兼容. 因?yàn)榉缎褪窃?code>jdk1.5之后才引入的. 在jdk1.5之前例如集合的操作都是沒(méi)有范型支持的, 所以生成的字節(jié)碼中參數(shù)都是用Object接收的, 所以也可以往集合中放入任意類(lèi)型的對(duì)象, 集合類(lèi)型的校驗(yàn)也被拖到運(yùn)行期.

但是在jdk1.5之后引入了范型, 因此集合的內(nèi)容校驗(yàn)被提前到了編譯期, 但是為了兼容jdk1.5之前的版本java使用了范型擦除, 所以如果不生成橋接方法就和jdk1.5之前的字節(jié)碼不兼容了.

上面可以看到在Parent.class中, 由于范型擦除, class文件中范型都是由Object替代了. 所以如果子類(lèi)中要是不生成bridge method那么子類(lèi)就沒(méi)有實(shí)現(xiàn)接口中的方法, 這個(gè)java語(yǔ)義就不對(duì)了(雖然已經(jīng)生成class文件了, 不會(huì)有編譯錯(cuò)誤)

4. 總結(jié)

因?yàn)?code>java要兼容之前的版本, 因此在一些步驟上要做一些trick操作, 但是這些trick操作又不能對(duì)用戶(hù)的使用產(chǎn)生困擾, 也就是說(shuō)這些操作對(duì)用戶(hù)應(yīng)該是透明的. 不得不說(shuō)java真的很強(qiáng)大, 我們平時(shí)用的只不過(guò)是java的冰山一角, 如果要更深入的了解java語(yǔ)言本身還有很多有意思的功能或者知識(shí)點(diǎn)需要了解.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窟哺,一起剝皮案震驚了整個(gè)濱河市肚邢,隨后出現(xiàn)的幾起案子胧砰,更是在濱河造成了極大的恐慌,老刑警劉巖锰蓬,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)窘疮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冀墨,“玉大人闸衫,你說(shuō)我怎么就攤上這事》碳危” “怎么了蔚出?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵疫蔓,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我身冬,道長(zhǎng)衅胀,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任酥筝,我火速辦了婚禮滚躯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘿歌。我一直安慰自己掸掏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布宙帝。 她就那樣靜靜地躺著丧凤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪步脓。 梳的紋絲不亂的頭發(fā)上愿待,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音靴患,去河邊找鬼仍侥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸳君,可吹牛的內(nèi)容都是我干的农渊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼或颊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼砸紊!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起囱挑,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤醉顽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后看铆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體徽鼎,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年弹惦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了否淤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棠隐,死狀恐怖石抡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情助泽,我是刑警寧澤啰扛,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布嚎京,位于F島的核電站,受9級(jí)特大地震影響隐解,放射性物質(zhì)發(fā)生泄漏鞍帝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一煞茫、第九天 我趴在偏房一處隱蔽的房頂上張望帕涌。 院中可真熱鬧,春花似錦续徽、人聲如沸蚓曼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纫版。三九已至,卻和暖如春客情,著一層夾襖步出監(jiān)牢的瞬間其弊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工裹匙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瑞凑,地道東北人末秃。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓概页,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親练慕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惰匙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評(píng)論 0 9
  • 在經(jīng)過(guò)一次沒(méi)有準(zhǔn)備的面試后铃将,發(fā)現(xiàn)自己雖然寫(xiě)了兩年的android代碼项鬼,基礎(chǔ)知識(shí)卻忘的差不多了。這是程序員的大忌劲阎,沒(méi)...
    猿來(lái)如癡閱讀 2,839評(píng)論 3 10
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法绘盟,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法悯仙,繼承相關(guān)的語(yǔ)法龄毡,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,623評(píng)論 18 399
  • 文――依陽(yáng) 01. 細(xì)細(xì)想來(lái)锡垄,我很少看纏綿悱惻的言情書(shū)籍沦零,也很少寫(xiě)關(guān)于愛(ài)情的任何文字。 若真要錙銖必較货岭,那便是讀過(guò)...
    依陽(yáng)吖閱讀 509評(píng)論 0 2
  • 每一個(gè)班主任都有許多潛在的得力幫手路操,只是有時(shí)候他自己沒(méi)發(fā)現(xiàn)或者沒(méi)用好罷了疾渴。比如我們學(xué)校,由學(xué)校層面安排的就有不少屯仗,...
    葉輝閱讀 328評(píng)論 5 0