前言

java有bridge方法,部分情况下会有用的。一些spring源码中也会根据bridge判断下不同逻辑。

介绍

java在JDK 1.5之后引入了泛型数据,为了使java的泛型犯法生成的字节码和1.5版本之前的字节码兼容,由编译器自动生成了该方法。同时,该方法也为泛型擦除做了准备。

  1. public class Modifier {
  2. static final int BRIDGE = 0x00000040;
  3. }
  4. public final class Method extends Executable {
  5. /**
  6. * Returns {@code true} if this method is a bridge
  7. * method; returns {@code false} otherwise.
  8. *
  9. * @return true if and only if this method is a bridge
  10. * method as defined by the Java Language Specification.
  11. * @since 1.5
  12. */
  13. public boolean isBridge() {
  14. return (getModifiers() & Modifier.BRIDGE) != 0;
  15. }
  16. }

反射中Mehtod类含有判断,来确定这个方法是不是桥接方法。

测试

这个桥接方法是编译器生成的,具体描述可见https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4.5

一般是父类含有泛型方法,子类在继承实现时,会由编译器实现这个方法。
例如:

  1. public abstract class C<T> {
  2. abstract T id(T x);
  3. }
  4. public class D extends C<String> {
  5. @Override
  6. String id(String x) {
  7. return x;
  8. }
  9. }
  10. //Test
  11. public static void main(String[] args) {
  12. C c = new D();
  13. c.id(new Object()); //ClassCastException
  14. }

如上所示,这里的类D中会生成桥接方法,可以通过命令查看:

  1. > javap -p D.class
  2. Compiled from "D.java"
  3. public class com.lean.bridge.D extends com.lean.bridge.C<java.lang.String> {
  4. public com.lean.bridge.D();
  5. java.lang.String id(java.lang.String);
  6. java.lang.Object id(java.lang.Object);
  7. }

通过javap命令就可以看到这里生成了一个额外的方法,且参数的类型是Object类型。这个方法的实现大概类似于:

  1. public Object id(Object o){
  2. return id((String)o);
  3. }

将参数进行转化,继而调用真正的方法。如果我们直接传递Object则不行,会报错:ClassCastException

原因

在java1.5之后,才引入了泛型,可以放入泛型类,但是java的泛型不是完全的,是执行了类型擦除后的,这是为了向前兼容1.5后的代码(感觉也是另一种选择方式)。所有的泛型参数都会变成Object,在代码编译时,来保证类型的正确。这里为了兼容1.5之前的字节码。这是其中的一个原因,另一个原因是为了兼容java的泛型擦除。

例如有如下代码:

  1. public <T> T max(List<T> list, Comparator<T> comp) {
  2. T biggestSoFar = list.get(0);
  3. for ( T t : list ) {
  4. if (comp.compare(t, biggestSoFar) > 0) {
  5. biggestSoFar = t;
  6. }
  7. }
  8. return biggestSoFar;
  9. }

在被java编译之后,真正的方法类似于如下:

  1. public Object max(List list, Comparator comp) {
  2. Object biggestSoFar = list.get(0);
  3. for ( Object t : list ) {
  4. if (comp.compare(t, biggestSoFar) > 0) { //IMPORTANT
  5. biggestSoFar = t;
  6. }
  7. }
  8. return biggestSoFar;
  9. }

当java编译成类似代码时,comp.compare(t, biggestSoFar)这里传递的都是Object类型,就没办法执行了。因为Comparator源码如下:

  1. public interface Comparator<T> {
  2. int compare(T var1, T var2);
  3. boolean equals(Object var1);
  4. }

它并没有接受Object类型的方法,有了桥接方法,这里就可以正常执行了。

使用

一般在使用时,可以通过method.isBridge()来检测是否是桥接方法。

如果想从桥接方法获取到对应的实际方法,则可以查看spring中org.springframework.core.BridgeMethodResolver类的源码来确定。这个源码也是根据参数类型,参数长度方法名称等等来判断了。

参考