Java泛型-桥接方法?

Java泛型-桥接方法?,java,generics,Java,Generics,与Java泛型相关的一个叫做“桥接方法”的概念让我停下来思考一下 顺便说一句,我只知道它发生在 字节码级别,不可用 供我们使用 但是我很想知道Java编译器使用的“桥接方法”背后的概念 幕后到底发生了什么,为什么要使用它 如果您能举个例子,我们将不胜感激 它是一种允许类扩展泛型类或实现泛型接口(带有具体类型参数)的方法,仍然用作原始类型 想象一下: public class MyComparator implements Comparator<Integer> { public

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

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

但是我很想知道Java编译器使用的“桥接方法”背后的概念

幕后到底发生了什么,为什么要使用它


如果您能举个例子,我们将不胜感激

它是一种允许类扩展泛型类或实现泛型接口(带有具体类型参数)的方法,仍然用作原始类型

想象一下:

public class MyComparator implements Comparator<Integer> {
   public int compare(Integer a, Integer b) {
      //
   }
}
编译器保护对桥接方法的访问,强制直接对其进行显式调用会导致编译时错误。现在,该类也可以以原始形式使用:

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;
}
如果桥接方法不存在,并且您将
列表
MyComparator
传递给此函数,在标记为
IMPORTANT
的行上的调用将失败,因为
MyComparator
将没有调用
compare
的方法,该方法接受两个
对象
s…只有一个方法接受两个
整数
s

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

另见:
  • (谢谢)

需要注意的是,编译器推断出
MyComparator
的方法:

public int compare(Integer a, Integer b) {/* code */}
正在尝试覆盖比较器的


从声明的类型
比较器
。否则,
MyComparator
compare
将被编译器视为附加(重载)方法,而不是重写方法。因此,不会为它创建桥接方法。

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

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);
  }
}
多态性在这里不起作用。请记住,您需要重写子类中父类的方法,以便可以使用父类变量触发多态性

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

如和所示,Java桥方法的关键原因是和

让我们以类()为例,它包含一个如下所示的
clone()
方法,因为类
ArrayDeque
实现了
Cloneable
接口,所以它必须重写
Object.clone()
方法

public class ArrayDeque<E> extends AbstractCollection<E>
                        implements Deque<E>, Cloneable, Serializable
{

  public ArrayDeque<E> clone() {
    ....
  }
}
返回类型不匹配是多态性的一个问题。因此,在编译的结果文件
ArrayDeque.class
中,Java编译器生成了两个
clone()
方法,一个匹配源代码中的签名,另一个匹配父类
Object.clone()
中的签名

  • 方法返回基于相应源代码生成的
    ArrayDeque
  • 方法返回基于
    Object.clone()
    生成的
    对象此方法只调用另一个
    clone()
    方法。
    此方法被标记为,这表明此方法是由编译器出于桥接目的生成的

  • 我无法解释得更清楚:(这恰好是谷歌的第一个结果)即使在没有泛型的情况下,协变返回类型也是如此。@paulmurray:“equals(to)”是什么?@gstackoverflow假设您有一个方法
    Object get()
    ,然后在子类中用
    String get()
    重写它。JVM将只覆盖完全匹配的签名,包括返回类型。因此,javac创建了一个合成桥方法
    Object get()
    (也称为
    get()Ljava/lang/Object;
    ),其实现调用
    String get()
    (也称为
    get()Ljava/lang/String;
    )。这仅在1.5版之后的源代码中才可能实现,并且您不能针对比源代码更早版本的字节码。@AndrewTobilko:是的,正如
    javap-v MyComparator.class
    所报告的,它是公开的。但是,正如我所提到的,编译器阻止您直接对参数化类型调用桥接方法,因此我认为它是“带有警告的public”。如果您查看
    javap
    的输出,您将看到桥接方法,尽管有
    ACC\u PUBLIC
    ,但有两个附加标志:
    ACC\u桥接
    ACC\u合成
    。编译器将研究如何使用它来禁止访问。@AndrewTobilko:注意,这并不意味着所有桥接方法都是公共的,只是我的示例中的一个。如果你用一个受保护的泛型方法扩展一个类(并给它一个具体的类型),然后用一个受保护的方法重写它,那么桥接方法将被保护以匹配。我检查了整个互联网,但发现你的答案非常简单和中肯。万分感谢。@SunnyKhan当我第一次看到桥牌法的时候就是我!幸运的是,我知道它是如何工作的!
    public int compare(T a, T b);
    
    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);
      }
    }
    
    A a=new B();
    a.set("Hello World!");
    
    public class ArrayDeque<E> extends AbstractCollection<E>
                            implements Deque<E>, Cloneable, Serializable
    {
    
      public ArrayDeque<E> clone() {
        ....
      }
    }
    
    public class Object {
    
        protected native Object clone() throws CloneNotSupportedException;
    }