午夜剧场伦理_日本一道高清_国产又黄又硬_91黄色网战_女同久久另类69精品国产_妹妹的朋友在线

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

3分鐘快速搞懂Java的橋接方法示例

瀏覽:142日期:2022-08-16 17:27:55
什么是橋接方法?

Java中的橋接方法(Bridge Method)是一種為了實(shí)現(xiàn)某些Java語(yǔ)言特性而由編譯器自動(dòng)生成的方法。

我們可以通過(guò)Method類(lèi)的isBridge方法來(lái)判斷一個(gè)方法是否是橋接方法。

在字節(jié)碼文件中,橋接方法會(huì)被標(biāo)記為ACC_BRIDGE和ACC_SYNTHETIC,其中ACC_BRIDGE用于表示該方法是由編譯器產(chǎn)生的橋接方法,ACC_SYNTHETIC用于表示該方法是由編譯器自動(dòng)生成。

什么時(shí)候生成橋接方法?

為了實(shí)現(xiàn)哪些Java語(yǔ)言特性會(huì)生成橋接方法?最常見(jiàn)的兩種情況就是協(xié)變返回值類(lèi)型和類(lèi)型擦除,因?yàn)樗鼈儗?dǎo)致了父類(lèi)方法的參數(shù)和實(shí)際調(diào)用的方法參數(shù)類(lèi)型不一致。下面我們通過(guò)兩個(gè)例子更好地理解一下。

協(xié)變返回類(lèi)型

協(xié)變返回類(lèi)型是指子類(lèi)方法的返回值類(lèi)型不必嚴(yán)格等同于父類(lèi)中被重寫(xiě)的方法的返回值類(lèi)型,而可以是更 “具體” 的類(lèi)型。

在Java 1.5添加了對(duì)協(xié)變返回類(lèi)型的支持,即子類(lèi)重寫(xiě)父類(lèi)方法時(shí),返回的類(lèi)型可以是子類(lèi)方法返回類(lèi)型的子類(lèi)。下面看一個(gè)例子:

public class Parent { Number get() { return 1; }}

public class Child extends Parent { @Override Integer get() { return 1; }}

Child類(lèi)重寫(xiě)其父類(lèi)Parent的get方法,Parent的get方法返回類(lèi)型為Number,而Child類(lèi)中g(shù)et方法返回類(lèi)型為Integer。

將這段代碼進(jìn)行編譯,再反編譯:

javac Child.javajavap -v -c Child.class

結(jié)果如下:

public class Child extends Parent......省略部分結(jié)果...... java.lang.Integer get(); descriptor: ()Ljava/lang/Integer; flags: Code: stack=1, locals=1, args_size=1 0: iconst_1 1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 4: areturn LineNumberTable:line 5: 0

java.lang.Number get(); descriptor: ()Ljava/lang/Number; flags: ACC_BRIDGE, ACC_SYNTHETIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokevirtual #3 // Method get:()Ljava/lang/Integer; 4: areturn LineNumberTable:line 1: 0

從上面的結(jié)果可以看到,有一個(gè)方法java.lang.Number get(), 在源碼中是沒(méi)有出現(xiàn)過(guò)的,是由編譯器自動(dòng)生成的,該方法被標(biāo)記為ACC_BRIDGE和ACC_SYNTHETIC,就是我們前面所說(shuō)的橋接方法。

這個(gè)方法就起了一個(gè)橋接的作用,它所做的就是把對(duì)自身的調(diào)用通過(guò)invokevirtual指令再調(diào)用方法java.lang.Integer get()。

**編譯器這么做的原因是什么呢?**因?yàn)樵贘VM方法中,返回類(lèi)型也是方法簽名的一部分,而橋接方法的簽名和其父類(lèi)的方法簽名一致,以此就實(shí)現(xiàn)了協(xié)變返回值類(lèi)型。

類(lèi)型擦除

泛型是Java 1.5才引進(jìn)的概念,在這之前是沒(méi)有泛型的概念的,但泛型代碼能夠很好地和之前版本的代碼很好地兼容,這是為什么呢?

這是因?yàn)椋诰幾g期間Java編譯器會(huì)將類(lèi)型參數(shù)替換為其上界(類(lèi)型參數(shù)中extends子句的類(lèi)型),如果上界沒(méi)有定義,則默認(rèn)為Object,這就叫做類(lèi)型擦除。

當(dāng)一個(gè)子類(lèi)在繼承(或?qū)崿F(xiàn))一個(gè)父類(lèi)(或接口)的泛型方法時(shí),在子類(lèi)中明確指定了泛型類(lèi)型,那么在編譯時(shí)編譯器會(huì)自動(dòng)生成橋接方法,例如:

public class Parent<T> { void set(T t) { }}

public class Child extends Parent<String> { @Override void set(String str) { }}

Child類(lèi)在繼承其父類(lèi)Parent的泛型方法時(shí),明確指定了泛型類(lèi)型為String,將這段代碼進(jìn)行編譯,再反編譯:

public class Child extends Parent<java.lang.String>......省略部分結(jié)果...... void set(java.lang.String); descriptor: (Ljava/lang/String;)V flags: Code: stack=0, locals=2, args_size=2 0: return LineNumberTable:line 5: 0

void set(java.lang.Object); descriptor: (Ljava/lang/Object;)V flags: ACC_BRIDGE, ACC_SYNTHETIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: checkcast #2 // class java/lang/String 5: invokevirtual #3 // Method set:(Ljava/lang/String;)V 8: return LineNumberTable:line 1: 0

從上面的結(jié)果可以看到,有一個(gè)方法void set(java.lang.Object), 在源碼中是沒(méi)有出現(xiàn)過(guò)的,是由編譯器自動(dòng)生成的,該方法被標(biāo)記為ACC_BRIDGE和ACC_SYNTHETIC,就是我們前面所說(shuō)的橋接方法。

這個(gè)方法就起了一個(gè)橋接的作用,它所做的就是把對(duì)自身的調(diào)用通過(guò)invokevirtual指令再調(diào)用方法void set(java.lang.String)。

**編譯器這么做的原因是什么呢?**因?yàn)镻arent類(lèi)在類(lèi)型擦除之后,變成這樣:

public class Parent<Object> { void set(Object t) { }}

編譯器為了讓子類(lèi)有一個(gè)與父類(lèi)的方法簽名一致的方法,就在子類(lèi)自動(dòng)生成一個(gè)與父類(lèi)的方法簽名一致的橋接方法。

如何獲取橋接方法的實(shí)際方法

在Spring Framework中已經(jīng)實(shí)現(xiàn)了獲取橋接方法的實(shí)際方法的功能,就在spring-core模塊中的BridgeMethodResolver類(lèi)中,像這樣直接使用就行了:

method = BridgeMethodResolver.findBridgedMethod(method);

findBridgedMethod方法是怎么實(shí)現(xiàn)的呢?我們來(lái)分析一下源碼(spring-core的版本為5.2.8.RELEASE):

public static Method findBridgedMethod(Method bridgeMethod) { // 如果不是橋連方法,就直接返回原方法。 if (!bridgeMethod.isBridge()) { return bridgeMethod; } // 先從本地緩存讀取,緩存中有則直接返回。 Method bridgedMethod = cache.get(bridgeMethod); if (bridgedMethod == null) { List<Method> candidateMethods = new ArrayList<>(); // 以方法名稱(chēng)和入?yún)€(gè)數(shù)相等為篩選條件。 MethodFilter filter = candidateMethod -> isBridgedCandidateFor(candidateMethod, bridgeMethod); // 遞歸該類(lèi)及其所有父類(lèi)上的所有方法,符合篩選條件就添加進(jìn)來(lái)。 ReflectionUtils.doWithMethods(bridgeMethod.getDeclaringClass() , candidateMethods::add, filter); if (!candidateMethods.isEmpty()) { // 如果符合篩選條件的方法個(gè)數(shù)為1,則直接采用; // 否則,調(diào)用searchCandidates方法再次篩選。 bridgedMethod = candidateMethods.size() == 1 ? candidateMethods.get(0) : searchCandidates(candidateMethods, bridgeMethod); } // 如果找不到實(shí)際方法,則返回原來(lái)的橋連方法。 if (bridgedMethod == null) { // A bridge method was passed in but we couldn’t find the bridged method. // Let’s proceed with the passed-in method and hope for the best... bridgedMethod = bridgeMethod; } // 把查找的結(jié)果放入內(nèi)存緩存。 cache.put(bridgeMethod, bridgedMethod); } return bridgedMethod;}

我們?cè)倏匆幌略俅魏Y選的searchCandidates方法是如何實(shí)現(xiàn)的:

private static Method searchCandidates(List<Method> candidateMethods, Method bridgeMethod) { if (candidateMethods.isEmpty()) { return null; } Method previousMethod = null; boolean sameSig = true; // 遍歷候選方法的列表 for (Method candidateMethod : candidateMethods) { // 對(duì)比橋接方法的泛型類(lèi)型參數(shù)和候選方法是否匹配,如果匹配則直接返回該候選方法。 if (isBridgeMethodFor(bridgeMethod, candidateMethod, bridgeMethod.getDeclaringClass())) { return candidateMethod; } else if (previousMethod != null) { // 如果不匹配,則判斷所有候選方法的參數(shù)列表是否相等。 sameSig = sameSig && Arrays.equals(candidateMethod.getGenericParameterTypes(), previousMethod.getGenericParameterTypes()); } previousMethod = candidateMethod; } // 如果所有候選方法的參數(shù)列表全相等,則返回第一個(gè)候選方法。 return (sameSig ? candidateMethods.get(0) : null);}

總結(jié)以上源碼就是,通過(guò)判斷方法名、參數(shù)的個(gè)數(shù)以及泛型類(lèi)型參數(shù)來(lái)獲取橋接方法的實(shí)際方法。

到此這篇關(guān)于3分鐘快速搞懂Java的橋接方法示例的文章就介紹到這了,更多相關(guān)Java 橋接內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 亚洲国产毛片 | 96国产精品 | 精品在线观看视频 | 四季av一区二区凹凸精品 | av大片在线观看 | 久久久久女教师免费一区 | 99国产精品久久久久 | 欧美日韩在线免费观看 | 欧美特黄一级 | 国产h在线观看 | 日本中文字幕在线播放 | 亚洲久久影院 | 五月婷婷六月香 | 日本成人综合 | 久久精品视频3 | 国产久操视频 | 福利视频亚洲 | 成人黄色免费视频 | 亚洲日本高清 | 成人免费毛片入口 | 日韩av在线看免费观看 | 久久久久久久久久免费视频 | 一区二区三区视频在线免费观看 | 日韩欧美在线观看视频 | 蜜臀av一区二区三区有限公司 | 久久99精品久久久久久 | 成年人视频网址 | 日韩在线中文 | 亚洲精品在线播放视频 | 亚洲在线网站 | 操她视频在线观看 | 五月婷在线视频 | 成人免费看片视频在线观看 | 国内免费精品视频 | 老司机午夜影院 | 中文字幕在线免费 | 午夜精品久久久久99蜜桃最新版 | 亚洲自拍在线观看 | 91在线小视频 | 日韩免费高清视频 | 禁网站在线观看免费视频 |