前言
java有bridge方法,部分情况下会有用的。一些spring源码中也会根据bridge判断下不同逻辑。
介绍
java在JDK 1.5之后引入了泛型数据,为了使java的泛型犯法生成的字节码和1.5版本之前的字节码兼容,由编译器自动生成了该方法。同时,该方法也为泛型擦除做了准备。
public class Modifier {
static final int BRIDGE = 0x00000040;
}
public final class Method extends Executable {
/**
* Returns {@code true} if this method is a bridge
* method; returns {@code false} otherwise.
*
* @return true if and only if this method is a bridge
* method as defined by the Java Language Specification.
* @since 1.5
*/
public boolean isBridge() {
return (getModifiers() & Modifier.BRIDGE) != 0;
}
}
反射中Mehtod
类含有判断,来确定这个方法是不是桥接方法。
测试
这个桥接方法是编译器生成的,具体描述可见https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4.5
一般是父类含有泛型方法,子类在继承实现时,会由编译器实现这个方法。
例如:
public abstract class C<T> {
abstract T id(T x);
}
public class D extends C<String> {
@Override
String id(String x) {
return x;
}
}
//Test
public static void main(String[] args) {
C c = new D();
c.id(new Object()); //ClassCastException
}
如上所示,这里的类D中会生成桥接方法,可以通过命令查看:
> javap -p D.class
Compiled from "D.java"
public class com.lean.bridge.D extends com.lean.bridge.C<java.lang.String> {
public com.lean.bridge.D();
java.lang.String id(java.lang.String);
java.lang.Object id(java.lang.Object);
}
通过javap命令就可以看到这里生成了一个额外的方法,且参数的类型是Object类型。这个方法的实现大概类似于:
public Object id(Object o){
return id((String)o);
}
将参数进行转化,继而调用真正的方法。如果我们直接传递Object则不行,会报错:ClassCastException
原因
在java1.5之后,才引入了泛型,可以放入泛型类,但是java的泛型不是完全的,是执行了类型擦除后的,这是为了向前兼容1.5后的代码(感觉也是另一种选择方式)。所有的泛型参数都会变成Object,在代码编译时,来保证类型的正确。这里为了兼容1.5之前的字节码。这是其中的一个原因,另一个原因是为了兼容java的泛型擦除。
例如有如下代码:
public <T> T max(List<T> list, Comparator<T> comp) {
T biggestSoFar = list.get(0);
for ( T t : list ) {
if (comp.compare(t, biggestSoFar) > 0) {
biggestSoFar = t;
}
}
return biggestSoFar;
}
在被java编译之后,真正的方法类似于如下:
public Object max(List list, Comparator comp) {
Object biggestSoFar = list.get(0);
for ( Object t : list ) {
if (comp.compare(t, biggestSoFar) > 0) { //IMPORTANT
biggestSoFar = t;
}
}
return biggestSoFar;
}
当java编译成类似代码时,comp.compare(t, biggestSoFar)
这里传递的都是Object类型,就没办法执行了。因为Comparator
源码如下:
public interface Comparator<T> {
int compare(T var1, T var2);
boolean equals(Object var1);
}
它并没有接受Object类型的方法,有了桥接方法,这里就可以正常执行了。
使用
一般在使用时,可以通过method.isBridge()
来检测是否是桥接方法。
如果想从桥接方法获取到对应的实际方法,则可以查看spring中org.springframework.core.BridgeMethodResolver类的源码来确定。这个源码也是根据参数类型,参数长度方法名称等等来判断了。