`
jiangshuiy
  • 浏览: 335512 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java中的桥方法

阅读更多

 

Java中的桥方法是合成方法(synthetic methods),合成方法对于实现Java语言特征是必需的。最广为人知的例子就是协变返回类型和泛型中的案例,在泛型中案例基方法的参数被擦除后与实际被调用的方法不同时会使用到桥方法。

 

首先来看一个例子:

 

public class BridgeMethodOne {
    public static class BMOne<T> {
        public T getT() {
            return null;
        }
    }

    public static class BMTwo extends BMOne<String> {
        public String getT() {
            return null;
        }
    }
}

 

      事实上这仅仅是一个协变返回类型的例子,在类型擦除之后看起来和下面的片段类似:

 

public class BridgeMethodOne {
    public static class BMOne {
        public Object getT() {
            return null;
        }
    }

    public static class BMTwo extends BMOne {
        public String getT() {
            return null;
        }
    }
}

     然后在编译反编译之后,BMTwo将和下面类似:

 

public static class learn.generic.BridgeMethodOne$BMTwo extends learn.generic.BridgeMethodOne$BMOne {

    .

  // Method descriptor #15 ()Ljava/lang/String;

  // Stack: 1, Locals: 1

  public java.lang.String getT();

    0  aconst_null

    1  areturn

    

 

  // Method descriptor #16 ()Ljava/lang/Object;

  // Stack: 1, Locals: 1

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

    0  aload_0 [this]

    1  invokevirtual learn.generic.BridgeMethodOne$BMTwo.getT() : java.lang.String [17]

4  areturn

}

 

 

在上面可以看见有一个新的合成方法“java.lang.Object getT()”,这是源代码中没有的。这个方法作为一个桥方法,它所做的全部工作就是将调用代理到“java.lang.String getT()”。因为在JVM里,方法的返回类型是方法签名的一部分,而创建桥方法是实现协变返回类型的方式,因此编译器必须这么做。

现在再来看下面这个泛型指定的例子:

 

public class BridgeMethodTwo {
    public static class BMOne<T> {
        public T getT(T args) {
            return args;
        }
    }

    public static class BMTwo extends BMOne<String> {
        public String getT(String args) {
            return args;
        }
    }
}

 在编译之后,BMTwo将被转换成如下:

 

public static class learn.generic.BridgeMethodTwo$BMTwo extends learn.generic.BridgeMethodTwo$BMOne {

   public java.lang.String getT(java.lang.String args);

    0  aload_1 [args]

    1  areturn

    

  // Method descriptor #18 (Ljava/lang/Object;)Ljava/lang/Object;

  // Stack: 2, Locals: 2

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

    0  aload_0 [this]

    1  aload_1 [arg0]

    2  checkcast java.lang.String [19]

    5  invokevirtual learn.generic.BridgeMethodTwo$BMTwo.getT(java.lang.String) : java.lang.String [21]

    8  areturn

}

 

 

 

在这里,桥方法重写了基类BMOne,它不仅做了有参数的调用,同时还执行了到“java.lang.String”的类型转换。这意味着在执行下面的代码忽略编译器的“uncheck”警告时,桥方法将抛出ClassCastException异常。

 

public static void main(String[] args) {
        BMOne one = new BMTwo();
        one.getT(new Object());
    }

 

 Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String

 

所列的两个例子是桥方法使用中最广为人知的,但除此之外,桥方法至少还有一个用武之地,那就是被用来改变基类方法的可见性。试着查看下面的例子并尝试着猜测编辑器需要在什么地方创建桥方法。

 

public class BridgeMethodThree {
    static class ClassA {
        public void foo() {
        }
    }

    public static class ClassB extends ClassA {
    }

    public static class ClassC extends ClassA {
        public void foo() {
        }
    }
} 

如果查看ClassB编译后的文件,可以发现发现:

public static class learn.generic.BridgeMethodThree$ClassB extends learn.generic.BridgeMethodThree$ClassA {

   public BridgeMethodThree$ClassB();

    0  aload_0 [this]

    1  invokespecial learn.generic.BridgeMethodThree$ClassA() [8]

    4  return

     

    public bridge synthetic void foo();

    0  aload_0 [this]

    1  invokespecial learn.generic.BridgeMethodThree$ClassA.foo() : void [15]

    4  return

 

}

 

因为ClassA是包级别限制的,不能被包外访问,而ClassB是公共的,而所有继承的方法必须能够被包外所访问,因此编译器需要桥方法。注意,由于ClassC重写了“foo”方法,不再需要桥方法来增加可见性。

也许还有一些其它地方使用了桥方法,但没有关于这些的源信息。同样,也没有桥方法的定义,虽然从上述的例子已经看出来并可以猜到大致代表什么,但JLS里却没有明确的说明。尽管isBridgejava1.5之后反射API了的公共方法,JVMJLS没有关于其的确切定义和编译器在何时、如何使用桥方法的定义。一般情况下,当一个类实现了一个参数化的接口或是继承了一个参数化的类时,需要引入桥方法。

 

英文参考:http://happyenjoylife.iteye.com/blog/1153964

              http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html

 

 

 

分享到:
评论

相关推荐

    详解java 中泛型中的类型擦除和桥方法

    主要介绍了详解java 中泛型中的类型擦除和桥方法的相关资料,需要的朋友可以参考下

    java数据库连接方法和实现

     JDBC-ODBC桥 这种类型的驱动把所有JDBC的调用传递给ODBC,再让后者调用数据库本地驱动代码(也就是数据库厂商提供的数据库操作二进制代码库,例如Oracle中的oci.dll)。 类型2  本地API驱动 这种类型的驱动通过...

    Java 8 简明教程 (Java 8 Tutorial中文版)文字pdf版

    Java 8 简明教程 Java 8 Tutorial中文版 “Java并没有没落,人们很快就会发现这一点” 欢迎阅读我编写的Java 8介绍。本教程将带领你一步一步地认识这门语言的新特 性。通过简单明了的代码示例,你将会学习到如何使用...

    JAVA上百实例源码以及开源项目

    在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...

    Java2实用教程.rar

    9 7在同步方法中使用wait notif 和nodf3 All 方法 9 8挂起 恢复和终止线程 9 9计时器线程Timer 9 10线程联合 9 11守护线程 习题 第10章输入输出流 10 1File类 10 2FileInputStream类 10 3FileOutputStream类 10 4...

    JAVA上百实例源码以及开源项目源代码

    在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...

    JAVA入门1.2.3:一个老鸟的JAVA学习心得 PART1(共3个)

    7.9.4 在构造方法中调用构造方法 184 7.10 方法大汇总 185 7.10.1 本例中用到的类 186 7.10.2 使用例程将本章的知识穿起来 189 7.11 小结:多方位理解Java方法 191 7.12 习题 192 第8章 Java中的包(Package)...

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    7.9.4 在构造方法中调用构造方法 184 7.10 方法大汇总 185 7.10.1 本例中用到的类 186 7.10.2 使用例程将本章的知识穿起来 189 7.11 小结:多方位理解Java方法 191 7.12 习题 192 第8章 Java中的包(Package)...

    java开源包6

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包11

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包9

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包101

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包4

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包5

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    Java案例开发锦集

    案例1 用户登录验证的完整程序 案例2 MD5的Javabean实现 案例3 用公钥计算消息摘要的验证码 案例4-1 Java中的数字证书的生成及维护方法 案例4-2 数字证书的签发(签名) 案例4-3 利用数字证书给...

    java开源包8

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java开源包10

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

    java连接数据库-odbcjdbc桥、连接池

    java连接数据库的两种方法详解,有配套实例,讲解清晰,通俗易懂。

    java 面试题 总结

    子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。...

    java开源包3

    Java的COM桥 JCom JCom (Java-COM Bridge) 可以让 Java 程序轻松访问 Windows 平台上的 COM 组件。 JARP JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and ...

Global site tag (gtag.js) - Google Analytics