Java Generics - Bridge Method?

2022-08-31 13:31:30

与Java泛型相关的“桥接方法”概念让我停下来思考一下。

顺便说一句,我只知道它发生在字节码级别,并且不可供我们使用。

但我渴望了解Java编译器使用的“桥接方法”背后的概念。

幕后究竟发生了什么,为什么使用它?

任何有关示例的帮助将不胜感激。


答案 1

这是一个允许扩展泛型类或实现泛型接口(具有具体类型参数)的类仍用作原始类型的方法。

想象一下:

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }
}

这不能以其原始形式使用,传递两个s进行比较,因为类型被编译到compare方法中(与泛型类型参数T的情况相反,其中类型将被擦除)。因此,相反,在幕后,编译器添加了一个“桥接方法”,它看起来像这样(如果它是Java源代码):Object

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }

   //THIS is a "bridge method"
   public int compare(Object a, Object b) {
      return compare((Integer)a, (Integer)b);
   }
}

编译器保护对 bridge 方法的访问,强制直接对它进行显式调用会导致编译时错误。现在,该类也可以以其原始形式使用:

Object a = 5;
Object b = 6;

Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);

为什么还需要它?

除了添加对显式使用原始类型的支持(主要用于向后兼容性)之外,还需要桥接方法来支持类型擦除。使用类型擦除,方法如下所示:

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;
}

实际上被编译成与此兼容的字节码:

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;
}

如果 bridge 方法不存在,并且您将 a 和 a 传递给此函数,则在标记的行处的调用将失败,因为不会调用需要两个 s 的方法。只有一个需要两个s。List<Integer>MyComparatorIMPORTANTMyComparatorcompareObjectInteger

下面的常见问题解答是一个很好的阅读。

另请参阅:


答案 2

如果你想了解为什么需要桥接方法,你最好理解没有它会发生什么。假设没有桥接方法。

class A<T>{
  private T value;
  public void set(T newVal){
    value=newVal
  }
}

class B extends A<String>{
  public void set(String newVal){
    System.out.println(newVal);
    super.set(newVal);
  }
}

请注意,擦除后,方法变成了,因为 Type 参数 没有绑定。类中没有一个方法的签名与 中相同。因此,没有覆盖。因此,当这样的事情发生时:setApublic void set(Object newVal)TBsetA

A a=new B();
a.set("Hello World!");

多态性在这里不起作用。请记住,您需要重写子类中父类的方法,以便可以使用父类 var 来触发多态性。

bridge 方法的作用是使用名称相同但签名不同的方法中的所有信息,以静默方式重写父类中的方法。在桥接方法的帮助下,多态性起作用了。尽管从表面上看,您使用具有不同签名的方法重写父类方法。


推荐