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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

合成和桥接方法

發(fā)布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 合成和桥接方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

如果您曾經(jīng)玩過反射并執(zhí)行了getDeclaredMethods()您可能會感到驚訝。 您可能會獲得源代碼中不存在的方法。 或者,也許您看了一些方法的修飾符,發(fā)現(xiàn)其中一些特殊方法是易變的。 順便說一句:對于Java采訪來說,這是一個令人討厭的問題,“當(dāng)方法易變時,這意味著什么?” 正確的答案是,方法不能是易變的。 同時,在getDeclaredMethods()甚至getMethods()返回的方法中,可能存在某些方法,其中Modifier.isVolatile(method.getModifiers())為true。

這是項目轉(zhuǎn)換器的用戶之一發(fā)生的 。 他意識到,交換器(本身會深入挖掘Java的黑暗細節(jié))生成的Java源代碼無法使用關(guān)鍵字volatile作為方法的修飾符進行編譯。 結(jié)果,它也不起作用。

那里發(fā)生了什么事? 橋接和合成方法是什么?

能見度

創(chuàng)建嵌套或嵌入式類時,可以從頂級類訪問嵌套類的私有變量和方法。 這由不可變的嵌入式構(gòu)建器模式使用 。 這是語言規(guī)范中定義的Java的明確定義的行為。

JLS7,6.6.1確定可訪問性
…如果成員或構(gòu)造函數(shù)被聲明為私有,則訪問為
當(dāng)且僅當(dāng)它出現(xiàn)在頂級類的主體中時才允許(第7.6節(jié))
包含成員或構(gòu)造函數(shù)的聲明…

package synthetic;public class SyntheticMethodTest1 {private A aObj = new A();public class A {private int i;}private class B {private int i = aObj.i;}public static void main(String[] args) {SyntheticMethodTest1 me = new SyntheticMethodTest1();me.aObj.i = 1;B bObj = me.new B();System.out.println(bObj.i);} }

JVM如何處理它? JVM不知道內(nèi)部或嵌套類。 對于JVM,所有類都是頂級外部類。 所有類都被編譯為頂級類,這就是那些不錯的方法...$. .class ...$. .class文件已創(chuàng)建。

$ ls -Fart ../ SyntheticMethodTest2$A.class MyClass.java SyntheticMethodTest4.java SyntheticMethodTest2.java SyntheticMethodTest2.class SyntheticMethodTest3.java ./ MyClassSon.java SyntheticMethodTest1.java

如果創(chuàng)建嵌套類或內(nèi)部類,它將被編譯為完整的頂級類。

外層如何提供私有字段? 如果這些人進入了真正的頂級階級并且是私人的,那么他們將如何從外部階級中獲得呢?

javac解決此問題的方式是,對于任何私有字段但從頂級類使用的字段,方法或構(gòu)造函數(shù),它都會生成綜合方法。 這些合成方法用于到達原始私有字段/方法/構(gòu)造函數(shù)。 這些方法的生成以巧妙的方式完成:僅生成真正需要并從外部使用的那些方法。

package synthetic;import java.lang.reflect.Constructor; import java.lang.reflect.Method;public class SyntheticMethodTest2 {public static class A {private A(){}private int x;private void x(){};}public static void main(String[] args) {A a = new A();a.x = 2;a.x();System.out.println(a.x);for (Method m : A.class.getDeclaredMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getName());}System.out.println("--------------------------");for (Method m : A.class.getMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());}System.out.println("--------------------------");for( Constructor<?> c : A.class.getDeclaredConstructors() ){System.out.println(String.format("%08X", c.getModifiers()) + " " + c.getName());}} }

由于生成的方法的名稱取決于實現(xiàn)方式,因此不能保證對上述程序的輸出所能說的最多的是,在我執(zhí)行該程序的特定平臺上,它產(chǎn)生了以下輸出:

2 00001008 access$1 00001008 access$2 00001008 access$3 00000002 x -------------------------- 00000111 void wait 00000011 void wait 00000011 void wait 00000001 boolean equals 00000001 String toString 00000101 int hashCode 00000111 Class getClass 00000111 void notify 00000111 void notifyAll -------------------------- 00000002 synthetic.SyntheticMethodTest2$A 00001000 synthetic.SyntheticMethodTest2$A

在上面的程序中,我們?yōu)樽侄蝬賦值,并且還調(diào)用了相同名稱的方法。 需要這些來觸發(fā)編譯器生成綜合方法。 您可以看到它生成了三種方法,大概是字段x的setter和getter以及方法x()的綜合方法。 但是,這些綜合方法未在getMethods()返回的下一個列表中列出,因為它們是綜合方法,因此不適用于通用調(diào)用。 從這種意義上講,它們是私有方法。

十六進制數(shù)字可以用作解釋器,查看類java.lang.reflect.Modifier定義的常量:

00001008 SYNTHETIC|STATIC 00000002 PRIVATE 00000111 NATIVE|FINAL|PUBLIC 00000011 FINAL|PUBLIC 00000001 PUBLIC 00001000 SYNTHETIC

列表中有兩個構(gòu)造函數(shù)。 有一個私人的和一個合成的。 私有存在,因為我們定義了它。 另一方面,合成的存在是因為我們從外部調(diào)用了私有的。 到目前為止,橋接方法還沒有。

泛型和繼承

到目前為止還不錯,但是我們?nèi)匀粵]有看到任何“易變”的方法。

查看java.lang.reflec.Modifier的源代碼,您會看到常量0x00000040定義了兩次。 一次是VOLATILE ,一次是BRIDGE (后者是私有程序包,不用于一般用途)。

要擁有這樣一種方法,一個非常簡單的程序就可以做到:

package synthetic;import java.lang.reflect.Method; import java.util.LinkedList;public class SyntheticMethodTest3 {public static class MyLink extends LinkedList<String> {@Overridepublic String get(int i) {return "";}}public static void main(String[] args) {for (Method m : MyLink.class.getDeclaredMethods()) {System.out.println(String.format("%08X", m.getModifiers()) + " " + m.getReturnType().getSimpleName() + " " + m.getName());}} }

我們有一個鏈表,該鏈表的方法get(int)返回String 。 我們不要討論干凈的代碼問題。 這是演示該主題的示例代碼。 干凈的代碼中也會出現(xiàn)相同的問題,盡管更復(fù)雜,并且在導(dǎo)致問題時更難指出問題所在。

輸出顯示:

00000001 String get 00001041 Object get

我們有兩個get()方法。 一個出現(xiàn)在源代碼中,另一個出現(xiàn)在合成和橋接中。 反編譯器javap表示生成的代碼是:

public java.lang.String get(int);Code:Stack=1, Locals=2, Args_size=20: ldc #2; //String2: areturnLineNumberTable:line 12: 0public java.lang.Object get(int);Code:Stack=2, Locals=2, Args_size=20: aload_01: iload_12: invokevirtual #3; //Method get:(I)Ljava/lang/String;5: areturn

有趣的是,這兩種方法的簽名是相同的,只是返回類型不同。 即使在Java語言中這是不可能的,但在JVM中允許這樣做。 bridge方法不執(zhí)行其他任何操作,而是調(diào)用原始方法。

為什么需要這種合成方法? 誰來使用它。 例如,想要使用類型MyLink的變量來調(diào)用方法get(int)的MyLink :

List<?> a = new MyLink();Object z = a.get(0);

它不能調(diào)用返回String的方法,因為List沒有這樣的方法。 為了使其更具說明性,讓我們重寫方法add()而不是get() :

package synthetic;import java.util.LinkedList; import java.util.List;public class SyntheticMethodTest4 {public static class MyLink extends LinkedList<String> {@Overridepublic boolean add(String s) {return true;}}public static void main(String[] args) {List a = new MyLink();a.add("");a.add(13);} }

我們可以看到橋接方法

public boolean add(java.lang.Object);Code:Stack=2, Locals=2, Args_size=20: aload_01: aload_12: checkcast #2; //class java/lang/String5: invokevirtual #3; //Method add:(Ljava/lang/String;)Z8: ireturn

不僅叫原版。 它還檢查類型轉(zhuǎn)換是否正確。 這是在運行時完成的,而不是由JVM本身完成的。 如您所料,它確實出現(xiàn)在第18行中:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Stringat synthetic.SyntheticMethodTest4$MyLink.add(SyntheticMethodTest4.java:1)at synthetic.SyntheticMethodTest4.main(SyntheticMethodTest4.java:18)

下次在面試中遇到關(guān)于不穩(wěn)定方法的問題時,您可能比面試官了解的更多。

參考: Java Deep博客中JCG合作伙伴 Peter Verhas的合成方法和橋接方法 。

翻譯自: https://www.javacodegeeks.com/2014/03/synthetic-and-bridge-methods.html

總結(jié)

以上是生活随笔為你收集整理的合成和桥接方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。