今天在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
分享到:
相关推荐
2. **Java.inc**:这是一个PHP扩展文件,包含PHP端的接口,用于在PHP代码中调用JavaBridge.jar中的类和方法。 三、集成与使用 在项目中使用PHP-Java-Bridge通常涉及以下步骤: 1. **安装JavaBridge.jar和Java.inc...
"java.inc" 文件是JavaBridge中的一个重要组成部分,它包含了一系列预定义的函数声明,这些函数用于在非Java代码中调用Java方法。开发者可以将这些函数包含到他们的项目中,然后就像调用本地函数一样调用Java方法。 ...
赠送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; 赠送...
如果你正在使用的辅助技术(如JAWS或NVDA)支持Java Access Bridge,你需要在辅助技术的设置中启用JAB。具体步骤取决于你使用的辅助技术,通常会在其文档中提供详细说明。 **4. 使用Java Access Bridge** JAB提供...
赠送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; 赠送...
赠送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从C#中获取Java应用程序的信息,你需要导入一个名为`JavaAccessBridge`的库,这个库实现了与Java Access Bridge的接口。在C#中,你可以创建一个`JavaVMInitArgs`对象来配置Java虚拟机(JVM...
赠送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 包含翻译后...
start javaw -jar JavaBridge.jar 保存后,双击启动 会有一个提示框选择vmbridge port 默认8080,直接点ok就行了 5.在/demo/下新建test.php内容如下: require_once ( "java/Java.inc" ); header( "content-type:...
赠送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通过HTTP请求与Java服务器交互时,php-servlet接收这些请求,解析它们,并将控制权传递给JavaBridge.jar中的适当方法。这个Servlet使得PHP代码能够以Web服务的方式调用Java服务,实现分布式计算。 3. **...
在提供的文件列表中,`JavaBridge.jar` 是 JavaBridge 的核心库文件,包含实现 PHP 和 Java 交互的类和方法。而 `java` 文件夹可能包含了运行 JavaBridge 所需的其他文件,如配置文件、Java 类库或者示例代码。 ...
Winsoft JavaBridge v3.0 for Delphi 组件是一个用于在 Delphi 程序中集成 Java 功能的工具。它提供了一个简单易用的接口,使开发人员可以在 Delphi 中调用和使用 Java 类和方法。该组件通过 Java 虚拟机 (JVM) 实现...
赠送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的...
在PHP中使用JavaBridge,你需要确保你的环境已经安装了Java运行时环境(JRE)以及PHP JavaBridge的相关扩展。 **步骤一:安装与配置** 1. 安装JavaBridge:下载并解压JavaBridge的最新版本(在这个例子中是6.2.1)...
JavaBridge 是一个软件开发工具,主要用于在Java和Delphi之间建立桥梁,允许开发者利用Java的类库和功能在Delphi环境中编写程序。这个版本是JavaBridge的2.7版,可能包含了对之前版本的一些改进和修复。从压缩包的...
1. **JavaBridge.jar**:这是PHP/Java Bridge的核心组件,它提供了一个Java服务器端接口,使得PHP能够调用Java类和方法。JavaBridge.jar通过HTTP协议工作,允许PHP代码通过HTTP请求与Java应用程序进行交互。这使得...
Java和JavaScript Bridge是一种技术,它允许Java代码与JavaScript代码之间进行通信,特别是在Android环境中,当在WebView中嵌入网页内容时,这种桥接技术尤为重要。这个开源项目"Java 和 Javascript Bridge 封装.zip...