java里面的bridge method

2017/07/11 Java

看springframework源码中关于ConfigurationClassParser在解析一个配置类的时候需要扫描某一配置类申明的带有@Bean注解所有方法,然后过滤掉bridge method,然后再继续解析。之前在看Java的泛型机制的时候有看到过关于bridge method,下面来介绍下相关概念。

先看下面这段代码:

public class Node<T> {

  public T data;

  public Node(T data) {
    this.data = data;
  }

  public void setData(T data) {
      System.out.println("Node.setData");
      this.data = data;
  }
}

public class MyNode extends Node<Integer> {

    public MyNode(Integer data) {
      super(data);
    }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }

    public static void main(String[] args){
    		MyNode mn = new MyNode(5);
    		Node n = mn;
    		n.setData("dddd");
    		String dd = (String)n.data;
    }
}

上面的代码编译不会出现问题,但是当运行时n.setData(“dddd”)这行会报错,为什么呢?熟悉Java泛型的都知道Java里面泛型只是一种语法糖,编译后其实会把泛型给擦除掉,擦除后的代码相当于下面这样:

public class Node {

    public Object data;

    public Node(Object data) { this.data = data; }

    public void setData(Object data) {
        System.out.println("Node.setData");
        this.data = data;
    }
}

public class MyNode extends Node {

    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

观察发现擦除后的代码会导致MyNode的setData方法没有对Node的setData方法形成覆盖。

为什么需要bridge method

所以对于上面这种情况,为了解决泛型擦除后保留多态的特性,Java编译器会生成synthetic方法也就是bridge method。如下:

class MyNode extends Node {

    // Bridge method generated by the compiler
    //
    public void setData(Object data) {
        setData((Integer) data);
    }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }

    // ...
}

针对于上面第一段代码运行时n.setData(“dddd”)报错,大家看了上面的代码后就知道为什么了。

其他生成bridge method的情况

同样,在java中子类Overriding父类方法的时候,由于返回类型可以不保持一模一样,这个时候如果不引入bridge method,则会造成方法的Overriding失效。

Search

    Table of Contents