Java Generics - Bridge Method?
与Java泛型相关的“桥接方法”概念让我停下来思考一下。
顺便说一句,我只知道它发生在字节码级别,并且不可供我们使用。
但我渴望了解Java编译器使用的“桥接方法”背后的概念。
幕后究竟发生了什么,为什么使用它?
任何有关示例的帮助将不胜感激。
与Java泛型相关的“桥接方法”概念让我停下来思考一下。
顺便说一句,我只知道它发生在字节码级别,并且不可供我们使用。
但我渴望了解Java编译器使用的“桥接方法”背后的概念。
幕后究竟发生了什么,为什么使用它?
任何有关示例的帮助将不胜感激。
这是一个允许扩展泛型类或实现泛型接口(具有具体类型参数)的类仍用作原始类型的方法。
想象一下:
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>
MyComparator
IMPORTANT
MyComparator
compare
Object
Integer
下面的常见问题解答是一个很好的阅读。
如果你想了解为什么需要桥接方法,你最好理解没有它会发生什么。假设没有桥接方法。
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 参数 没有绑定。类中没有一个方法的签名与 中相同。因此,没有覆盖。因此,当这样的事情发生时:set
A
public void set(Object newVal)
T
B
set
A
A a=new B();
a.set("Hello World!");
多态性在这里不起作用。请记住,您需要重写子类中父类的方法,以便可以使用父类 var 来触发多态性。
bridge 方法的作用是使用名称相同但签名不同的方法中的所有信息,以静默方式重写父类中的方法。在桥接方法的帮助下,多态性起作用了。尽管从表面上看,您使用具有不同签名的方法重写父类方法。