今天在
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在编译器层面上提供了支持。
分享到:
相关推荐
赠送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; 赠送...
赠送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; 赠送...
赠送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.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.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; 赠送...
C#通过java access bridge获取java应用程序的信息
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.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; 赠送...
Winsoft JavaBridge v3.0 for Delphi 组件是一个用于在 Delphi 程序中集成 Java 功能的工具。它提供了一个简单易用的接口,使开发人员可以在 Delphi 中调用和使用 Java 类和方法。该组件通过 Java 虚拟机 (JVM) 实现...
php-java-bridge_6.2.1_documentation php调用java代码使用javabridge
php,java混编所依赖的JavaBridge包,一般导入项目时,只需要JavaBridge.jar和Java.Inc这两个文件
PHP/Java Bridge的JavaBridge.jar、php-servlet.jar和php-script.jar
基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的开发源码-PHPJava Bridge.zip 基于java的...
JavaBridge 2.7
使用JAB来实现java代码控制java窗口的工具,网上资料很少,自己的研究也有限,希望多多指教
JavaBridge + java.inc
ava Access Bridge 是一项在 Microsoft Windows DLL 中公开 Java Accessibility API 的技术,可以使实现 Java Accessibility API 的 Java 应用程序和小程序对 Microsoft Windows 系统上的辅助技术可见。Java ...
PHP/Java bridge , call php in java and call jacva in php. Java as backend and php as a front end.
Jacob 是 JAVA-COM Bridge的缩写,是一个中间件,能够提供自动化访问MS系统下COM组件和Win32 libraries的功能。 • MS系统提供的COM组件 COM组件 对象ID MS Word Word.Application MS Excel Excel.Application MS ...