<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中字節(jié)碼的格式的時候,發(fā)現(xiàn)method_info中的access_flags中竟然定了ACC_BRIDGE的值。網(wǎng)上搜了一下,大概理解它的意思了,先記之。

     

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

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

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

    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中則沒有。事實(shí)上,由于Java中泛型有擦除的機(jī)制,因而在編譯A類的時候,它里面定義的方法都是以Object類型來表示了,因而如果沒有bridge方法,B類根本沒有覆蓋A類中的abstract方法。正因?yàn)橛?/span>bridge方法的存在,才使得B類可以編譯通過。而C類由于在編譯時所有的泛型也都是通過Object類來表達(dá)的,因而它實(shí)現(xiàn)的也是A類中的abstract方法,因而不用再生成bridge方法了。

     

    事實(shí)上B類中的bridge方法在調(diào)用也有一些區(qū)別:

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

     

    這段方法的字節(jié)碼如下:

         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變量調(diào)用的method1(String)的方法,而a變量調(diào)用的卻是method1(Object)方法。這種區(qū)別也正式因?yàn)?/span>bridge方法提供的支持才實(shí)現(xiàn)的。

     

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

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

    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的字節(jié)碼:

    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

    }

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

    從調(diào)用的字節(jié)碼上可以更加明顯的看出語法沒有發(fā)生變化這一點(diǎn):

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

     

    字節(jié)碼如下:

     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

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

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

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

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

    FeedBack:
    # re: Java中的Bridge方法
    2014-01-22 10:19 | gelato
    主站蜘蛛池模板: 亚洲成片观看四虎永久| 亚洲国语精品自产拍在线观看| 杨幂最新免费特级毛片| 亚洲精品无码久久久久| 最近免费中文字幕mv在线电影| 中国亚洲呦女专区| 亚洲最大av资源站无码av网址| 免费一级毛片在线播放| 久章草在线精品视频免费观看| 中文字幕精品三区无码亚洲| 国产亚洲精品不卡在线| 日韩免费精品视频| 亚洲视频在线免费| 久久国产亚洲精品| 亚洲国产无套无码av电影| 毛片a级毛片免费观看免下载| 岛国精品一区免费视频在线观看| 亚洲伊人久久大香线蕉啊| 国产精品亚洲mnbav网站| 久久天天躁狠狠躁夜夜免费观看| 一级美国片免费看| 亚洲AV无码无限在线观看不卡| 亚洲中文字幕日产乱码高清app| 最近中文字幕无免费视频| 久久精品国产影库免费看| 国产亚洲视频在线观看| 亚洲一级片在线播放| 亚洲无线码一区二区三区| 国产精品国产免费无码专区不卡| 久久国产色AV免费观看| 成人福利在线观看免费视频| 国产亚洲大尺度无码无码专线| 国产香蕉九九久久精品免费| 久久亚洲免费视频| 亚欧洲精品在线视频免费观看 | 日本高清免费不卡视频| 嫩草成人永久免费观看| 一本久久免费视频| 亚洲AV永久无码精品网站在线观看| 亚洲精品在线免费看| 亚洲国产精品无码久久久秋霞2 |