`
不爱不见
  • 浏览: 285971 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java中的Bridge方法

阅读更多
今天在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而不是F的bridge方法。

从调用的字节码上可以更加明显的看出语法没有发生变化这一点:

    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在编译器层面上提供了支持。

                              摘自:http://www.blogjava.net/DLevin/archive/2011/06/23/352917.html
分享到:
评论

相关推荐

    php-java-bridge_7.2.1_documentation.zip

    2. **Java.inc**:这是一个PHP扩展文件,包含PHP端的接口,用于在PHP代码中调用JavaBridge.jar中的类和方法。 三、集成与使用 在项目中使用PHP-Java-Bridge通常涉及以下步骤: 1. **安装JavaBridge.jar和Java.inc...

    JavaBridge下载

    "java.inc" 文件是JavaBridge中的一个重要组成部分,它包含了一系列预定义的函数声明,这些函数用于在非Java代码中调用Java方法。开发者可以将这些函数包含到他们的项目中,然后就像调用本地函数一样调用Java方法。 ...

    flink-table-api-java-bridge_2.11-1.12.7-API文档-中文版.zip

    赠送jar包:flink-table-api-java-bridge_2.11-1.12.7.jar; 赠送原API文档:flink-table-api-java-bridge_2.11-1.12.7-javadoc.jar; 赠送源代码:flink-table-api-java-bridge_2.11-1.12.7-sources.jar; 赠送...

    JAB(java access bridge)安装和使用

    如果你正在使用的辅助技术(如JAWS或NVDA)支持Java Access Bridge,你需要在辅助技术的设置中启用JAB。具体步骤取决于你使用的辅助技术,通常会在其文档中提供详细说明。 **4. 使用Java Access Bridge** JAB提供...

    flink-table-api-java-bridge_2.12-1.14.3-API文档-中英对照版.zip

    赠送jar包:flink-table-api-java-bridge_2.12-1.14.3.jar; 赠送原API文档:flink-table-api-java-bridge_2.12-1.14.3-javadoc.jar; 赠送源代码:flink-table-api-java-bridge_2.12-1.14.3-sources.jar; 赠送...

    flink-table-api-java-bridge_2.11-1.13.2-API文档-中英对照版.zip

    赠送jar包:flink-table-api-java-bridge_2.11-1.13.2.jar; 赠送原API文档:flink-table-api-java-bridge_2.11-1.13.2-javadoc.jar; 赠送源代码:flink-table-api-java-bridge_2.11-1.13.2-sources.jar; 赠送...

    Java Access bridge 小应用

    要使用Java Access Bridge从C#中获取Java应用程序的信息,你需要导入一个名为`JavaAccessBridge`的库,这个库实现了与Java Access Bridge的接口。在C#中,你可以创建一个`JavaVMInitArgs`对象来配置Java虚拟机(JVM...

    flink-table-api-java-bridge_2.12-1.14.3-API文档-中文版.zip

    赠送jar包:flink-table-api-java-bridge_2.12-1.14.3.jar 赠送原API文档:flink-table-api-java-bridge_2.12-1.14.3-javadoc.jar 赠送源代码:flink-table-api-java-bridge_2.12-1.14.3-sources.jar 包含翻译后...

    php-java-bridge 配置包

    start javaw -jar JavaBridge.jar 保存后,双击启动 会有一个提示框选择vmbridge port 默认8080,直接点ok就行了 5.在/demo/下新建test.php内容如下: require_once ( "java/Java.inc" ); header( "content-type:...

    flink-table-api-java-bridge_2.11-1.10.0-API文档-中文版.zip

    赠送jar包:flink-table-api-java-bridge_2.11-1.10.0.jar; 赠送原API文档:flink-table-api-java-bridge_2.11-1.10.0-javadoc.jar; 赠送源代码:flink-table-api-java-bridge_2.11-1.10.0-sources.jar; 赠送...

    PHP/Java Bridge的JavaBridge.jar、php-servlet.jar和php-script.jar

    当PHP通过HTTP请求与Java服务器交互时,php-servlet接收这些请求,解析它们,并将控制权传递给JavaBridge.jar中的适当方法。这个Servlet使得PHP代码能够以Web服务的方式调用Java服务,实现分布式计算。 3. **...

    JavaBridge

    在提供的文件列表中,`JavaBridge.jar` 是 JavaBridge 的核心库文件,包含实现 PHP 和 Java 交互的类和方法。而 `java` 文件夹可能包含了运行 JavaBridge 所需的其他文件,如配置文件、Java 类库或者示例代码。 ...

    Winsoft JavaBridge v3.0 for Delphi Full Source.rar

    Winsoft JavaBridge v3.0 for Delphi 组件是一个用于在 Delphi 程序中集成 Java 功能的工具。它提供了一个简单易用的接口,使开发人员可以在 Delphi 中调用和使用 Java 类和方法。该组件通过 Java 虚拟机 (JVM) 实现...

    flink-table-api-java-bridge_2.11-1.13.2-API文档-中文版.zip

    赠送jar包:flink-table-api-java-bridge_2.11-1.13.2.jar; 赠送原API文档:flink-table-api-java-bridge_2.11-1.13.2-javadoc.jar; 赠送源代码:flink-table-api-java-bridge_2.11-1.13.2-sources.jar; 赠送...

    基于java的开发源码-PHPJava Bridge.zip

    基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的...

    PHP通过javabridge6.2.1调用 Java的说明及源代码(可运行)

    在PHP中使用JavaBridge,你需要确保你的环境已经安装了Java运行时环境(JRE)以及PHP JavaBridge的相关扩展。 **步骤一:安装与配置** 1. 安装JavaBridge:下载并解压JavaBridge的最新版本(在这个例子中是6.2.1)...

    JavaBridge 2.7.rar

    JavaBridge 是一个软件开发工具,主要用于在Java和Delphi之间建立桥梁,允许开发者利用Java的类库和功能在Delphi环境中编写程序。这个版本是JavaBridge的2.7版,可能包含了对之前版本的一些改进和修复。从压缩包的...

    将PHP/Java Bridge的JavaBridge.jar、php-servlet.jar和php-script.jar

    1. **JavaBridge.jar**:这是PHP/Java Bridge的核心组件,它提供了一个Java服务器端接口,使得PHP能够调用Java类和方法。JavaBridge.jar通过HTTP协议工作,允许PHP代码通过HTTP请求与Java应用程序进行交互。这使得...

    Java 和 Javascript Bridge 封装.zip

    Java和JavaScript Bridge是一种技术,它允许Java代码与JavaScript代码之间进行通信,特别是在Android环境中,当在WebView中嵌入网页内容时,这种桥接技术尤为重要。这个开源项目"Java 和 Javascript Bridge 封装.zip...

Global site tag (gtag.js) - Google Analytics