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