Kaedah penjembatan digunakan oleh pengkompil untuk menjadikan kod bait yang dihasilkan oleh kaedah generik java serasi dengan kod bait sebelum jdk1.5 selepas pengenalan generik dalam jdk1. 5 Dijana secara automatik.
Anda boleh menggunakan method.isBridge()
untuk menentukan sama ada kaedah itu adalah kaedah jambatan akan terdapat bendera bertanda ACC_BRIDGE, ACC_SYNTHETIC dalam kod bait yang dijana mengikut rajah bendera akses daripada Pemahaman Mendalam tentang Mesin Maya Java , anda boleh melihat perwakilan ACC_BRIDGE Kaedah adalah kaedah jambatan yang dijana oleh pengkompil ACC_SYNTHETIC menunjukkan bahawa kaedah dijana secara automatik oleh pengkompil dan bukan milik kod sumber.
Apabila subkelas mewarisi kelas induk (antara muka diwarisi) untuk melaksanakan kaedah generik abstrak, pengkompil akan secara automatik menjana kaedah jambatan untuk subkelas
#父类 public abstract class SuperClass<T> { public abstract T get(T t) ; } #子类 public class SubClass extends SuperClass<String> { @Override public String get(String s) { return s; } }
Gunakan perintah javap -v SubClass.class
untuk melihat kod bait SubKelas kelas:
Classfile /Users/xudong/project-maven/test/person-study/dubbo-provider/target/classes/com/monian/dubbo/provider/study/generic/SubClass.class Last modified 2022年7月25日; size 777 bytes MD5 checksum 1328a7043cde4b809a156e7a239335a6 Compiled from "SubClass.java" public class com.monian.dubbo.provider.study.generic.SubClass extends com.monian.dubbo.provider.study.generic.SuperClass<java.lang.String> minor version: 0 major version: 52 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #4 // com/monian/dubbo/provider/study/generic/SubClass super_class: #5 // com/monian/dubbo/provider/study/generic/SuperClass interfaces: 0, fields: 0, methods: 3, attributes: 2 Constant pool: #1 = Methodref #5.#23 // com/monian/dubbo/provider/study/generic/SuperClass."<init>":()V #2 = Class #24 // java/lang/String #3 = Methodref #4.#25 // com/monian/dubbo/provider/study/generic/SubClass.get:(Ljava/lang/String;)Ljava/lang/String; #4 = Class #26 // com/monian/dubbo/provider/study/generic/SubClass #5 = Class #27 // com/monian/dubbo/provider/study/generic/SuperClass #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 LocalVariableTable #11 = Utf8 this #12 = Utf8 Lcom/monian/dubbo/provider/study/generic/SubClass; #13 = Utf8 get #14 = Utf8 (Ljava/lang/String;)Ljava/lang/String; #15 = Utf8 s #16 = Utf8 Ljava/lang/String; #17 = Utf8 MethodParameters #18 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object; #19 = Utf8 Signature #20 = Utf8 Lcom/monian/dubbo/provider/study/generic/SuperClass<Ljava/lang/String;>; #21 = Utf8 SourceFile #22 = Utf8 SubClass.java #23 = NameAndType #6:#7 // "<init>":()V #24 = Utf8 java/lang/String #25 = NameAndType #13:#14 // get:(Ljava/lang/String;)Ljava/lang/String; #26 = Utf8 com/monian/dubbo/provider/study/generic/SubClass #27 = Utf8 com/monian/dubbo/provider/study/generic/SuperClass { public com.monian.dubbo.provider.study.generic.SubClass(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method com/monian/dubbo/provider/study/generic/SuperClass."<init>":()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/monian/dubbo/provider/study/generic/SubClass; public java.lang.String get(java.lang.String); descriptor: (Ljava/lang/String;)Ljava/lang/String; flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=2, args_size=2 0: aload_1 1: areturn LineNumberTable: line 11: 0 LocalVariableTable: Start Length Slot Name Signature 0 2 0 this Lcom/monian/dubbo/provider/study/generic/SubClass; 0 2 1 s Ljava/lang/String; MethodParameters: Name Flags s public java.lang.Object get(java.lang.Object); descriptor: (Ljava/lang/Object;)Ljava/lang/Object; flags: (0x1041) ACC_PUBLIC, 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 get:(Ljava/lang/String;)Ljava/lang/String; 8: areturn LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this Lcom/monian/dubbo/provider/study/generic/SubClass; MethodParameters: Name Flags s synthetic } Signature: #20 // Lcom/monian/dubbo/provider/study/generic/SuperClass<Ljava/lang/String;>; SourceFile: "SubClass.java"
Anda boleh melihat bahawa terdapat dua kaedah mendapatkan dalam bytecode , parameter kaedah kedua dan jenis nilai pulangan ialah java.lang.Object dan anda boleh melihat bahawa bendera mempunyai bendera yang sepadan ACC_BRIDGE dan ACC_SYNTHETIC, menunjukkan bahawa kaedah ini ialah kaedah jambatan yang dijana secara automatik oleh pengkompil. Lihat atribut kod sekali lagi:
aload_0: Muatkan pembolehubah ini ke dalam tindanan operan
aload_1: Muatkan pembolehubah kaedah s ke dalam tindanan operan
cast semak # 2: Sahkan sama ada pembolehubah s di bahagian atas tindanan adalah daripada jenis java.lang.String
invokevirtual # 3: Panggil kaedah public String get(String s)
return: Kembalikan hasil
Generik Java akan dipadamkan dan digantikan dengan sempadan atas bukan generik pada masa jalan dan mesin maya Java tidak dapat mengetahui jenis yang tepat. Kod di atas boleh disusun dan akan memanggil kaedah jambatan subkelas SubClass, dan kemudian kaedah jambatan akan memanggil kaedah generik sebenar. Jika ia ditakrifkan sebagaipublic String get(String s) { return s; } #桥接方法 public Object get(Object s) { return get((String) s); }, maka parameter input kaedah get hanya boleh menjadi pembolehubah String, kerana pengkompil akan melakukan semakan jenis semasa penyusunan, dan jika jenis tidak sepadan dengan jenis, ia akan melaporkan kegagalan kompilasi secara langsung. 3. Mengapakah kaedah generik dijana
public class SubClass extends SuperClass<String> { @Override public String get(String s) { return s; } public static void main(String[] args) { SuperClass subClass = new SubClass(); Object s = "hello world"; System.out.println(subClass.get(s)); } }
SuperClassf7e83be87db5cd2d9a8a0b8117b38cd4 subClass = new SubClass();
Untuk menyusun dengan betul, anda boleh melihat bahawa jenis parameter kelas induk SuperClass get dalam kod sumber ialah T (T t), dan dalam sari kata Pada peringkat kod, anda boleh melihat bahawa selepas penyusunan, jenis input dan nilai pulangan kaedah get adalah kedua-duanya Objek.
{ public com.monian.dubbo.provider.study.generic.SuperClass(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 7: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/monian/dubbo/provider/study/generic/SuperClass; LocalVariableTypeTable: Start Length Slot Name Signature 0 5 0 this Lcom/monian/dubbo/provider/study/generic/SuperClass<TT;>; public abstract T get(T); descriptor: (Ljava/lang/Object;)Ljava/lang/Object; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT MethodParameters: Name Flags t Signature: #18 // (TT;)TT; }4. Dapatkan kaedah generik sebenar berdasarkan kaedah jambatan Terutamanya gunakan Spring's BridgeMethodResolver#findBridgedMethod Prinsipnya ialah mencari dahulu semua kaedah yang diisytiharkan oleh kelas. Kaedah mencari dan merapatkan adalah mudah dengan nama dan bilangan parameter kaedah yang sama Jika terdapat hanya satu, ia akan dikembalikan secara langsung sama atau kaedah calon mempunyai tandatangan kaedah yang sama, dan kemudian mana-mana satu daripada kaedah tersebut akan dipilih sebagai kaedah tersusun.
@Slf4j public class SubClass extends SuperClass<String> { @Override public String get(String s) { return s; } public static void main(String[] args) throws Exception { SubClass subClass = new SubClass(); Method bridgeMethod = subClass.getClass().getDeclaredMethod("get", Object.class); log.info("bridgeMethod is bridge:" + bridgeMethod.isBridge()); log.info("bridgeMethod:" + bridgeMethod.toString()); // 实际泛型方法 Method actualMethod = subClass.getClass().getDeclaredMethod("get", String.class); log.info("actualMethod:" + actualMethod.toString()); // 通过spring #BridgeMethodResolver由桥接方法获取到实际泛型方法 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); log.info("bridgedMethod:" + bridgedMethod.toString()); } }
Atas ialah kandungan terperinci Cara menggunakan kaedah penyambungan Java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!