前言
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> {@OverrideString id(String x) {return x;}}//Testpublic static void main(String[] args) {C c = new D();c.id(new Object()); //ClassCastException}
如上所示,这里的类D中会生成桥接方法,可以通过命令查看:
> javap -p D.classCompiled 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) { //IMPORTANTbiggestSoFar = 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类的源码来确定。这个源码也是根据参数类型,参数长度方法名称等等来判断了。
