java - 桥接方法
原因
- 使用范型 (类型擦除后为了兼容父类方法)
- 子类返回值的类型和父类的返回值不致
分析
// Father.java
public interface Father<T> {
String hello(T data);
Object say();
}
//Son.java
public class Son implements Father<String> {
@Override
public String hello(String data) {
return data;
}
/**
* 重写父类方法后修改返回值类型
* @return
*/
@Override
public Integer say() {
return 1;
}
}
Father 类中的字节码:
public abstract interface com/ddup/Father {
// compiled from: Father.java
// access flags 0x401
// signature (TT;)Ljava/lang/String;
// declaration: java.lang.String hello(T)
public abstract hello(Ljava/lang/Object;)Ljava/lang/String;
// access flags 0x401
public abstract say()Ljava/lang/Object;
}
Son 类中的字节码:
public class com/ddup/Son implements com/ddup/Father {
// compiled from: Son.java
// access flags 0x1
// 构造函数
public <init>()V
L0
LINENUMBER 3 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/ddup/Son; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public hello(Ljava/lang/String;)Ljava/lang/String;
L0
LINENUMBER 6 L0
ALOAD 1
ARETURN
L1
LOCALVARIABLE this Lcom/ddup/Son; L0 L1 0
LOCALVARIABLE data Ljava/lang/String; L0 L1 1
MAXSTACK = 1
MAXLOCALS = 2
// access flags 0x1
public say()Ljava/lang/Integer;
L0
LINENUMBER 16 L0
ICONST_1
INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
ARETURN
L1
LOCALVARIABLE this Lcom/ddup/Son; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1041
// 桥接方法
public synthetic bridge say()Ljava/lang/Object;
L0
LINENUMBER 3 L0
ALOAD 0
INVOKEVIRTUAL com/ddup/Son.say ()Ljava/lang/Integer;
ARETURN
L1
LOCALVARIABLE this Lcom/ddup/Son; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1041
// 桥接方法
public synthetic bridge hello(Ljava/lang/Object;)Ljava/lang/String;
L0
LINENUMBER 3 L0
ALOAD 0
ALOAD 1
CHECKCAST java/lang/String
INVOKEVIRTUAL com/ddup/Son.hello (Ljava/lang/String;)Ljava/lang/String;
ARETURN
L1
LOCALVARIABLE this Lcom/ddup/Son; L0 L1 0
MAXSTACK = 2
MAXLOCALS = 2
}
可以发现,桥接的方法 就是父类类型擦除之后的方法,不过最终还是调用了子类中类型强制转换之后的方法:
// 差不多是这个意思
public String hello(Object data) {
return son.hello((String)data);
}
注意事项
在反射获取方法的时候需要考虑这个问题 !!