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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

slf4j 桥接与被桥接_合成和桥接方法

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

slf4j 橋接與被橋接

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

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

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

能見度

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

JLS7,6.6.1確定可訪問性

…如果成員或構造函數被聲明為私有,則訪問為
當且僅當它出現在頂級類的主體中時才允許(第7.6節)
包含成員或構造函數的聲明…

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不知道內部或嵌套類。 對于JVM,所有類都是頂級外部類。 所有類都被編譯為頂級類,這就是那些不錯的方法...$. .class ...$. .class文件已創建。

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

如果創建嵌套或內部類,它將被編譯為完整的頂級類。

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

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

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());}} }

由于生成的方法的名稱取決于實現方式,因此不能保證對上述程序的輸出最多的是,在我執行該程序的特定平臺上,它會產生以下輸出:

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

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

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

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

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

泛型和繼承

到目前為止,還不錯,但是我們仍然沒有看到任何“易變”的方法。

查看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 。 我們不要討論干凈的代碼問題。 這是演示該主題的示例代碼。 干凈的代碼中也會出現同樣的問題,盡管更復雜,更難在出現問題時解決。

輸出顯示:

00000001 String get 00001041 Object get

我們有兩個get()方法。 一個出現在源代碼中,另一個出現在源代碼中并且是合成的。 反編譯器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

有趣的是,這兩種方法的簽名是相同的,只是返回類型不同。 JVM允許這樣做,即使Java語言無法做到這一點。 bridge方法不執行其他任何操作,而是調用原始方法。

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

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

它不能調用返回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

不僅叫原版。 它還檢查類型轉換是否正確。 這是在運行時完成的,而不是由JVM本身完成的。 如您所料,它確實出現在第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)

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

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

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

slf4j 橋接與被橋接

總結

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

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