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);
}
}
注意,擦除之后,方法 set 在 A 成为 public void set(Object newVal) 因为类型参数没有绑定 T . 类中没有方法 B 其签名与 set 在 A . 所以没有覆盖。因此,当这样的事情发生时:
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);
}
}
编译器保护对网桥方法的访问,强制直接显式调用它会导致编译时错误。现在该类也可以以其原始形式使用:
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;
}
4条答案
按热度按时间oyjwcjzk1#
如果您想了解为什么需要桥接方法,那么最好了解没有桥接方法会发生什么。假设没有桥接法。
注意,擦除之后,方法
set
在A
成为public void set(Object newVal)
因为类型参数没有绑定T
. 类中没有方法B
其签名与set
在A
. 所以没有覆盖。因此,当这样的事情发生时:多态性在这里不起作用。记住,您需要重写子类中父类的方法,以便可以使用父类var触发多态性。
网桥方法所做的是使用来自同名但签名不同的方法的所有信息,以静默方式重写父类中的方法。在桥接方法的帮助下,多态性起了作用。虽然在表面上,您使用不同签名的方法重写父类方法。
nimxete22#
正如本文和本文所指出的,java桥方法的关键原因是类型擦除和多态性。
让我们以类arraydeque(源代码)为例,它包含
clone()
方法如下,因为类ArrayDeque
实现Cloneable
所以它必须重写Object.clone()
方法。但问题是返回类型
ArrayDeque.clone()
是ArrayDeque<E>
,并且它与父级中定义的方法签名不匹配Object.clone()
,在object.java中,返回类型为Object
相反。返回类型不匹配是多态性的一个问题。所以在编译的结果文件中
ArrayDeque.class
,java编译器生成了两个clone()
方法,一个匹配源代码中的签名,另一个匹配父类中的签名Object.clone()
.clone()方法返回
ArrayDeque<E>
,它是根据相应的源代码生成的clone()方法返回
Object
,它是基于Object.clone()
. 这个方法除了调用另一个以外什么也不做clone()
方法。并且,这个方法被标记为acc_bridge,这表示这个方法是由编译器为桥接目的生成的。omjgkv6w3#
它是一种允许类扩展泛型类或实现泛型接口(带有具体类型参数)仍用作原始类型的方法。
想象一下:
这不能用在它的原始形式中,传递2
Object
s进行比较,因为类型被编译到compare方法中(与泛型类型参数t相反,在泛型类型参数t中类型将被删除)。因此,在幕后,编译器添加了一个“桥方法”,看起来像这样(如果是java源代码):编译器保护对网桥方法的访问,强制直接显式调用它会导致编译时错误。现在该类也可以以其原始形式使用:
为什么还需要它?
除了添加对原始类型显式使用的支持(这主要是为了向后兼容)之外,还需要桥接方法来支持类型擦除。对于类型擦除,使用如下方法:
实际编译成字节码,与此兼容:
如果桥接方法不存在而您通过了
List<Integer>
和一个MyComparator
对于此函数,行中的调用IMPORTANT
从此失败MyComparator
不会调用任何方法compare
那需要两个人Object
s、 …只有一个需要两个Integer
s。下面的常见问题是一个很好的阅读。
另请参见:
泛型常见问题-什么是桥接方法?
java桥方法解释(感谢@bozho)
cfh9epnr4#
值得注意的是,编译器推断
MyComparator
的方法:正在试图覆盖
Comparator<T>
的从声明的类型
Comparator<Integer>
. 否则,MyComparator
的compare
将被编译器视为附加(重载)方法,而不是重写方法。因此,没有为它创建桥接方法。