Bridge方法和泛型
看API的时候,发现java.lang.reflect.Method类里有个isBridge方法。那,什么是bridge呢?下面开始的是关于这个问题的学习。
在JLS里对Bridge Method有这么一段描述
As an example of such a situation, consider the declarations:
Now, given an invocationclass C<T> { abstract T id(T x); }
class D extends C<String> { String id(String x) { return x; } }
The erasure of the actual method being invoked, differs in its signature from that of the compile-time method declaration,C c = new D();
c.id(new Object()); // fails with a ClassCastException
C.id()
. The former takes an argument of type String
while the latter takes an argument of type Object
. The invocation fails with a ClassCastException
before the body of the method is executed.Such situations can only arise if the program gives rise to an unchecked warning (§5.1.9).
Implementations can enforce these semantics by creating bridge methods. In the above example, the following bridge method would be created in class D
:
This is the method that would actually be invoked by the Java virtual machine in response to the callObject id(Object x) { return id((String) x); }
c.id(new Object())
下面试写了两个简单的类,并对照查看了他们对应的class文件
Test.ava
1 package bridgemethod;
2
3 public class Test {}
4
5 class Father<T>{
6
7 T elm;
8
9 T doSomething(T elm){
10 return elm;
11 }
12 }
13
14 class Son extends Father<String>{
15 @Override
16 String doSomething(String elm){
17 return elm;
18 }
19 }
2
3 public class Test {}
4
5 class Father<T>{
6
7 T elm;
8
9 T doSomething(T elm){
10 return elm;
11 }
12 }
13
14 class Son extends Father<String>{
15 @Override
16 String doSomething(String elm){
17 return elm;
18 }
19 }
Father.class
1 // Compiled from Test.java (version 1.6 : 50.0, super bit)
2 // Signature: <T:Ljava/lang/Object;>Ljava/lang/Object;
3 class bridgemethod.Father {
4
5 // Field descriptor #6 Ljava/lang/Object;
6 // Signature: TT;
7 java.lang.Object elm;
8
9 // Method descriptor #10 ()V
10 // Stack: 1, Locals: 1
11 Father();
12 0 aload_0 [this]
13 1 invokespecial java.lang.Object() [12]
14 4 return
15 Line numbers:
16 [pc: 0, line: 5]
17 Local variable table:
18 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Father
19 Local variable type table:
20 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Father<T>
21
22 // Method descriptor #21 (Ljava/lang/Object;)Ljava/lang/Object;
23 // Signature: (TT;)TT;
24 // Stack: 1, Locals: 2
25 java.lang.Object doSomething(java.lang.Object elm);
26 0 aload_1 [elm]
27 1 areturn
28 Line numbers:
29 [pc: 0, line: 10]
30 Local variable table:
31 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Father
32 [pc: 0, pc: 2] local: elm index: 1 type: java.lang.Object
33 Local variable type table:
34 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Father<T>
35 [pc: 0, pc: 2] local: elm index: 1 type: T
36 }
2 // Signature: <T:Ljava/lang/Object;>Ljava/lang/Object;
3 class bridgemethod.Father {
4
5 // Field descriptor #6 Ljava/lang/Object;
6 // Signature: TT;
7 java.lang.Object elm;
8
9 // Method descriptor #10 ()V
10 // Stack: 1, Locals: 1
11 Father();
12 0 aload_0 [this]
13 1 invokespecial java.lang.Object() [12]
14 4 return
15 Line numbers:
16 [pc: 0, line: 5]
17 Local variable table:
18 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Father
19 Local variable type table:
20 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Father<T>
21
22 // Method descriptor #21 (Ljava/lang/Object;)Ljava/lang/Object;
23 // Signature: (TT;)TT;
24 // Stack: 1, Locals: 2
25 java.lang.Object doSomething(java.lang.Object elm);
26 0 aload_1 [elm]
27 1 areturn
28 Line numbers:
29 [pc: 0, line: 10]
30 Local variable table:
31 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Father
32 [pc: 0, pc: 2] local: elm index: 1 type: java.lang.Object
33 Local variable type table:
34 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Father<T>
35 [pc: 0, pc: 2] local: elm index: 1 type: T
36 }
注意:第七行原本的T elm被替换成了java.lang.Object elm。
注意:第二十五行doSomething的参数和返回值同样被替换了。
Son.class
1 // Compiled from Test.java (version 1.6 : 50.0, super bit)
2 // Signature: Lbridgemethod/Father<Ljava/lang/String;>;
3 class bridgemethod.Son extends bridgemethod.Father {
4
5 // Method descriptor #6 ()V
6 // Stack: 1, Locals: 1
7 Son();
8 0 aload_0 [this]
9 1 invokespecial bridgemethod.Father() [8]
10 4 return
11 Line numbers:
12 [pc: 0, line: 14]
13 Local variable table:
14 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Son
15
16 // Method descriptor #15 (Ljava/lang/String;)Ljava/lang/String;
17 // Stack: 1, Locals: 2
18 java.lang.String doSomething(java.lang.String elm);
19 0 aload_1 [elm]
20 1 areturn
21 Line numbers:
22 [pc: 0, line: 17]
23 Local variable table:
24 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Son
25 [pc: 0, pc: 2] local: elm index: 1 type: java.lang.String
26
27 // Method descriptor #18 (Ljava/lang/Object;)Ljava/lang/Object;
28 // Stack: 2, Locals: 2
29 bridge synthetic java.lang.Object doSomething(java.lang.Object arg0);
30 0 aload_0 [this]
31 1 aload_1 [arg0]
32 2 checkcast java.lang.String [19]
33 5 invokevirtual bridgemethod.Son.doSomething(java.lang.String) : java.lang.String [21]
34 8 areturn
35 Line numbers:
36 [pc: 0, line: 1]
37 }
2 // Signature: Lbridgemethod/Father<Ljava/lang/String;>;
3 class bridgemethod.Son extends bridgemethod.Father {
4
5 // Method descriptor #6 ()V
6 // Stack: 1, Locals: 1
7 Son();
8 0 aload_0 [this]
9 1 invokespecial bridgemethod.Father() [8]
10 4 return
11 Line numbers:
12 [pc: 0, line: 14]
13 Local variable table:
14 [pc: 0, pc: 5] local: this index: 0 type: bridgemethod.Son
15
16 // Method descriptor #15 (Ljava/lang/String;)Ljava/lang/String;
17 // Stack: 1, Locals: 2
18 java.lang.String doSomething(java.lang.String elm);
19 0 aload_1 [elm]
20 1 areturn
21 Line numbers:
22 [pc: 0, line: 17]
23 Local variable table:
24 [pc: 0, pc: 2] local: this index: 0 type: bridgemethod.Son
25 [pc: 0, pc: 2] local: elm index: 1 type: java.lang.String
26
27 // Method descriptor #18 (Ljava/lang/Object;)Ljava/lang/Object;
28 // Stack: 2, Locals: 2
29 bridge synthetic java.lang.Object doSomething(java.lang.Object arg0);
30 0 aload_0 [this]
31 1 aload_1 [arg0]
32 2 checkcast java.lang.String [19]
33 5 invokevirtual bridgemethod.Son.doSomething(java.lang.String) : java.lang.String [21]
34 8 areturn
35 Line numbers:
36 [pc: 0, line: 1]
37 }
注意:Song.class里有三个方法。多出来的是方法在第二十九行