• 當前位置:首頁 > IT技術 > 其他 > 正文

    泛型之橋接方法
    2022-08-29 23:57:52

    ?什么是橋接方法

      在 JDK1.5 中引入了泛型,泛型類型是基于原始類型、類型擦除原理進行實現的。那么JDK1.5有了泛型怎么兼容JDK1.5之前的類?
      原始類型:Java總是會自動的為泛型類型提供一個相應的原始類型。所謂原始類型就是是指泛型的第一個限定類型(從左向右),無限定類型泛型的原始類型默認為Object。
      類型擦除:Java中泛型的實現原理是類型擦除(type erasure)。類型擦除是在編譯器進行代碼編譯這個階段進行的,在編譯的時候泛型的類型參數會被原始類型(raw type)所替代。
      橋接方法是在父類、子類的繼承場景中出現的。父類是泛型類,且在該類中存在泛型方法。子類繼承父類,并實現泛型方法。如果在子類實現中不包含父類經過類型擦除后生成的原始類型方法,則編譯器會自動將該原始類型方法添加到子類中。這個被添加的原始類型方法我們稱之為橋接方法。

    看個例子

     ?。?)首先定義一個父類接口SuperClass

    public interface SuperClass<T>{
        void test(T t);
    }

      我們來看下字節碼文件??javap -verbose SuperClass.class,只有一個test方法。

    ?。?)定義一個子類實現類BaseClass

    public class BaseClass implements SuperClass<String>{
        @Override
        public void test(String s) {
            
        }
    }

      看下BaseClass的字節碼文件,發現類中多了一個方法 public void test(java.lang.Object);這個就是本文要討論的橋接方法。

      PS:ACC_BRIDGE 修飾符表示這是一個橋接方法。ACC_SYNTHETIC修飾符表示這個方法是由編譯器自動生成的。

     ?

    (3)定義一個BaseClass的擴展類SubClass(子類),擴展其他方法

    public class SubClass extends BaseClass{
        public void run() {
            System.out.println("run---");
        }
    }

      查看字節碼文件,只有一個run方法。

      

      SubClass重寫父類test方法

    public class SubClass extends BaseClass{
        public void run() {
            System.out.println("run---");
        }
        @Override
        public void test(String s) {
            System.out.println("SubClass.test(s)");
        }
    }

      再次查看字節碼文件,生成了橋接方法public void test(java.lang.Object);  

    ?

      那么我們是否可以推測出:橋接方法是伴隨泛型方法而生的,在繼承關系中,如果某個子類覆蓋了泛型方法,則編譯器會在該子類中自動生成橋接方法。

    那么為什么要生成橋接方法?

      父接口SuperClass定義了test方法,SuperClass經過類型擦除轉換為原始類型后,會生成 public void test(java.lang.Object); 方法,我們在SuperClass的子類定義了泛型的具體類型,導致子類中的 test方法變化為 public void test(String s);,
      那么此時父類的 public void test(java.lang.Object); 是沒有被實現的,為了解決這個問題,Java 編譯器通過橋接的方式實現了 public void test(java.lang.Object); 方法。
      這樣就保證了SuperClass與子類具有相同的一致的方法 public void test(java.lang.Object); 。在訪問泛型對象時,通過父類方法 test進行統一調用,而不需要關注子類的具體實現。

    橋接方法的執行過程

      找個有橋接方法的類,我們看下字節碼文件, 比如BaseClass

      public void test(java.lang.Object); 這個方法真正執行的是public void test(String s);?

    怎么判斷一個方法是否是橋接方法?

      通過 method.isBridge() 可以判定是否為橋接方法。

        public static void main(String[] args) throws Exception{
            BaseClass baseClass = new BaseClass();
            Method method1 = BaseClass.class.getMethod("test", String.class);
            method1.invoke(baseClass,"ABC");
            System.out.println(method1.isBridge());
            Method method2 = BaseClass.class.getMethod("test", Object.class);
            method2.invoke(baseClass,"ABC");
            System.out.println(method2.isBridge());
        }

    ?

    使用場景

      在 Mybatis中, MapperAnnotationBuilder 類的 parse 方進行了橋接方法的判定。

      我們使用反射調用方法時,也需要考慮橋接方法是否處理。

    ?

    ?

    ?

    ?

    ?

      

     

    ?

    本文摘自 :https://www.cnblogs.com/

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码