Today, in Java, we found that the value of ACC_BRIDGE was set in access_flags in method_info. I searched it online and probably understood it. Remember it first.
First, under what circumstances will the bridge method be generated (2 ):
Bridge method may be created by the compiler when extending a parameterized type whose methods have parameterized arguments.
This is a post posted on the Internet, but it doesn't seem quite clear. First, the bridge method is generated by the compiler, so there is no bridge keyword in the source code. Then, the inherited generic class contains the generic method only when the specific type is inherited from a generic class. For example, see the following example:
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;
}
}
The. class file they generated is as follows:
A. class
Abstract class org. levin. insidejvm. miscs. bridgemethod. {
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. {
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. {
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
}
We can see that B generates two bridge methods, but C does not. In fact, Java generics have an erasure mechanism, so when compiling Class A, all the methods defined in it are represented by the Object type. Therefore, if there is no bridge method, class B does not cover the abstract method in Class A at all. Because of the existence of the bridge method, Class B can be compiled. The C class implements the abstract method in Class A because all generics are expressed through the Object class during compilation, so the bridge method does not need to be generated.
In fact, the bridge method in Class B also has some differences in calling:
Public static void main (String [] args ){
B B = new B ();
B. method1 ("abc ");
A <String> a = new B ();
A. method1 ("abc ");
}
The bytecode of this method is as follows:
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
The above code shows the method1 (String) method called by variable B, while variable a calls the method1 (Object) method. This difference is also officially achieved by the support provided by the bridge method.
In fact, the bridge method will generate in another case (2 ):
In Java 1.4, to override a method of the parent class, the method signature of the subclass must be consistent with that of the parent class, including the method name, parameter type, and return value; in Java 1.5, this mechanism becomes: if the method name and parameter type of a method in the subclass are the same as that of a method in the parent class, in addition, if the return value of a subclass method is the type of the return value of the parent method or its subtype, The subclass method can also override the corresponding method in the parent class. See the following example:
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 ();
}
}
The above code can be compiled. Let's take a look at the byte code of 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
}
From the bytecode, we can see that the syntax itself has not actually changed. The only difference is the support of the compiler. It re-generates a bridge method that returns E instead of F for the overload method.
From the byte code of the call, we can see that the syntax has not changed:
Public static void main (String [] args ){
X x = new Y ();
X. getE ();
}
The bytecode is as follows:
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
In this bytecode, the x. getE () method actually calls the generated bridge method (E getE () instead of the User-Defined F getE () method.
In some cases, the return of a function of different subclasses