<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    上善若水
    In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
    posts - 146,comments - 147,trackbacks - 0

    今天在Java中字節碼的格式的時候,發現method_info中的access_flags中竟然定了ACC_BRIDGE的值。網上搜了一下,大概理解它的意思了,先記之。

     

    首先是在什么情況下會生成bridge方法(2):

    bridge method may be created by the compiler when extending a parameterized type whose methods have parameterized arguments.

    這是在網上找到的有人貼出來的一段話,但是感覺這段話說的并不是很明白。首先bridge方式是由編譯器產生的,因而在源代碼中也沒有bridge的關鍵字。然后只有在以具體類型繼承自一個泛型類,同時被繼承的泛型類包含了泛型方法。比如看以下的例子:

    abstract class A<T> {
        
    public abstract T method1(T arg);
        
    public abstract T method2();
    }
     
    class B extends A<String> {
        
    public String method1(String arg) {
           
    return arg;
        }
        
    public String method2() {
           
    return "abc";
        }
    }
     
    class C<T> extends A<T> {
        
    public T method1(T arg) {
           
    return arg;
        }
       
        
    public T method2() {
           
    return null;
        }
    }

     

     

    他們生成的.class文件如下:

    A.class

    abstract class org.levin.insidejvm.miscs.bridgemethod.A {

     public abstract java.lang.Object method1(java.lang.Object arg0);

     public abstract java.lang.Object method2();

    }

    B.class

    class org.levin.insidejvm.miscs.bridgemethod.B extends org.levin.insidejvm.miscs.bridgemethod.A {

     public java.lang.String method1(java.lang.String arg);

        0 aload_1 [arg]

        1 areturn

     public java.lang.String method2();

        0 ldc <String "abc"> [20]

        2 areturn

     public bridge synthetic java.lang.Object method2();

        0 aload_0 [this]

        1 invokevirtual org.levin.insidejvm.miscs.bridgemethod.B.method2() : java.lang.String [23]

        4 areturn

      public bridge synthetic java.lang.Object method1(java.lang.Object arg0);

        0 aload_0 [this]

        1 aload_1 [arg0]

        2 checkcast java.lang.String [26]

        5 invokevirtual org.levin.insidejvm.miscs.bridgemethod.B.method1(java.lang.String) : java.lang.String [28]

        8 areturn

    }

    C.class

    class org.levin.insidejvm.miscs.bridgemethod.C extends org.levin.insidejvm.miscs.bridgemethod.A {

      public java.lang.Object method1(java.lang.Object arg);

        0 aload_1 [arg]

        1 areturn

     public java.lang.Object method2();

        0 aconst_null

        1 areturn

    }

    可以看到B中生成了兩個bridge方法,而C中則沒有。事實上,由于Java中泛型有擦除的機制,因而在編譯A類的時候,它里面定義的方法都是以Object類型來表示了,因而如果沒有bridge方法,B類根本沒有覆蓋A類中的abstract方法。正因為有bridge方法的存在,才使得B類可以編譯通過。而C類由于在編譯時所有的泛型也都是通過Object類來表達的,因而它實現的也是A類中的abstract方法,因而不用再生成bridge方法了。

     

    事實上B類中的bridge方法在調用也有一些區別:

        public static void main(String[] args) {
           B b 
    = new B();
           b.method1(
    "abc");
           A
    <String> a = new B();
           a.method1(
    "abc");
        }

     

    這段方法的字節碼如下:

         0 new org.levin.insidejvm.miscs.bridgemethod.B [16]

         3 dup

         4 invokespecial org.levin.insidejvm.miscs.bridgemethod.B() [18]

         7 astore_1 [b]

         8 aload_1 [b]

         9 ldc <String "abc"> [19]

        11 invokevirtual org.levin.insidejvm.miscs.bridgemethod.B.method1(java.lang.String) : java.lang.String [21]

        14 pop

        15 new org.levin.insidejvm.miscs.bridgemethod.B [16]

        18 dup

        19 invokespecial org.levin.insidejvm.miscs.bridgemethod.B() [18]

        22 astore_2 [a]

        23 aload_2 [a]

        24 ldc <String "abc"> [19]

        26 invokevirtual org.levin.insidejvm.miscs.bridgemethod.A.method1(java.lang.Object) : java.lang.Object [25]

        29 pop

        30 return

    以上的代碼可以看出b變量調用的method1(String)的方法,而a變量調用的卻是method1(Object)方法。這種區別也正式因為bridge方法提供的支持才實現的。

     

    事實上,bridge方法還會在另外一種情況下產生(2):

    Java 1.4中,子類若要重寫父類某個方法,那么子類的方法和父類的方法簽名必須完全一致,包括方法名、參數類型以及返回值;而到Java 1.5中,該機制變成,如果子類中某個方法的方法名和參數類型和父類某方法一致,并且子類該方法的返回值是父類相應方法返回值的類型或其子類型,那么該子類方法也可以重寫父類中相應的方法。參看以下例子:

    class E {
       
    }
     
    class F extends E {
       
    }
     
    class X {
        
    public E getE() {
           
    return new E();
        }
    }
     
    class Y extends X {
        @Override
        
    public F getE() {
           
    return new F();
        }
    }

     

    以上代碼是可以編譯通過的。讓我們再來查看一下Y的字節碼:

    class org.levin.insidejvm.miscs.bridgemethod.Y extends org.levin.insidejvm.miscs.bridgemethod.X {

      public org.levin.insidejvm.miscs.bridgemethod.F getE();

        0 new org.levin.insidejvm.miscs.bridgemethod.F [16]

        3 dup

        4 invokespecial org.levin.insidejvm.miscs.bridgemethod.F() [18]

        7 areturn

     public bridge synthetic org.levin.insidejvm.miscs.bridgemethod.E getE();

        0 aload_0 [this]

        1 invokevirtual org.levin.insidejvm.miscs.bridgemethod.Y.getE() : org.levin.insidejvm.miscs.bridgemethod.F [20]

        4 areturn

    }

    從字節碼上,我們可以看出語法本身事實上并沒有發生變化,變化的只是編譯器做的支持,它為重載方法重新生成了一個返回E而不是Fbridge方法。

    從調用的字節碼上可以更加明顯的看出語法沒有發生變化這一點:

        public static void main(String[] args) {
           X x 
    = new Y();
           x.getE();
        }

     

    字節碼如下:

     public static void main(java.lang.String[] args);

         0 new org.levin.insidejvm.miscs.bridgemethod.Y [16]

         3 dup

         4 invokespecial org.levin.insidejvm.miscs.bridgemethod.Y() [18]

        7 astore_1 [x]

         8 aload_1 [x]

         9 invokevirtual org.levin.insidejvm.miscs.bridgemethod.X.getE() : org.levin.insidejvm.miscs.bridgemethod.E [19]

        12 pop

    13 return

    該字節碼中x.getE()方法事實上調用的就是生成的bridge方法(E getE())方法,而不是用戶定義的F getE()方法。

    這種重載機制在某些,不同子類某個函數的返回值是不一樣的,但是他們都需要重寫父類中方法,以可以在某個點上通過父類實例統一調用。只是這種機制就需要返回值必須是繼承于同一個類。事實上,這種方式在沒有引入這種重寫機制的時候也是可以實現的,只是現在Java在編譯器層面上提供了支持。

                                                                                                                        于2010年10月3日
    注:這些文章都是前些時候寫的,之前博客很亂,也都是隨便貼一些自己寫的或轉載的,還有一些則是沒有貼出來過的。現在打算好好整理一下,完整的記錄自己的一些學習歷程,而每次看到過去的時間,則讓我想起以前的日子,因而我對時間一直是很重視的,所以每篇都著名寫的日期,直到最先的文章出現。:)

    posted on 2011-06-23 23:54 DLevin 閱讀(5169) 評論(1)  編輯  收藏 所屬分類: Core Java

    FeedBack:
    # re: Java中的Bridge方法
    2014-01-22 10:19 | gelato
    好  回復  更多評論
      
    主站蜘蛛池模板: 杨幂最新免费特级毛片| 亚洲精品蜜夜内射| 大地资源中文在线观看免费版 | 最新亚洲人成无码网www电影| 亚洲五月激情综合图片区| 波霸在线精品视频免费观看| 我们的2018在线观看免费高清| 亚洲视频免费在线观看| 久久狠狠躁免费观看2020| 亚洲?V乱码久久精品蜜桃 | 在线观看免费国产视频| 亚洲AV日韩AV高潮无码专区| 十八禁视频在线观看免费无码无遮挡骂过| 亚洲成a人片在线观看国产| 亚洲专区一路线二| 中文字幕免费不卡二区| 久久亚洲国产精品五月天| 亚洲成人在线免费观看| 中文字幕精品无码亚洲字| 成全视频免费观看在线看| 亚洲精品视频在线| 在线观看永久免费| 亚洲色偷偷综合亚洲AV伊人蜜桃| 国产又黄又爽又刺激的免费网址 | 拨牐拨牐x8免费| 色婷婷亚洲一区二区三区| 亚洲av中文无码| 免费毛片在线看不用播放器 | 伊人久久五月丁香综合中文亚洲| 精品久久久久久久免费人妻| 黄床大片30分钟免费看| 亚洲美女又黄又爽在线观看| 黄页网站在线观看免费| 亚洲无人区午夜福利码高清完整版| 日本免费电影一区二区| 亚洲人成免费网站| 男女免费观看在线爽爽爽视频 | 日韩亚洲人成在线| 好男人视频社区精品免费| 亚洲熟妇无码八V在线播放| 免费永久看黄在线观看app|