与Java Generics相关的称为"桥接方法"概念的东西让我停下来思考它.
顺便说一句,我只知道它出现在字节码级别,我们无法使用.
但我很想知道Java编译器使用的"桥接方法"背后的概念.
幕后究竟发生了什么以及为何使用它?
任何有关示例的帮助将不胜感激.
Mar*_*ers 80
它是一种允许扩展泛型类或实现泛型接口(具有具体类型参数)的类仍然可以用作原始类型的方法.
想象一下:
public class MyComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
//
}
}
Run Code Online (Sandbox Code Playgroud)
这不能以其原始形式使用,传递两个Object
s进行比较,因为类型被编译到比较方法(与通用类型参数T,其中类型将被擦除的情况相反).因此,在幕后,编译器添加了一个"桥接方法",看起来像这样(它是Java源代码):
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);
}
}
Run Code Online (Sandbox Code Playgroud)
编译器保护对bridge方法的访问,强制直接对其进行显式调用会导致编译时错误.现在这个类也可以以原始形式使用:
Object a = 5;
Object b = 6;
Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);
Run Code Online (Sandbox Code Playgroud)
除了添加对原始类型的显式使用的支持(主要用于向后兼容性)之外,还需要桥接方法来支持类型擦除.使用类型擦除,这样的方法:
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;
}
Run Code Online (Sandbox Code Playgroud)
实际上编译成与此兼容的字节码:
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;
}
Run Code Online (Sandbox Code Playgroud)
如果bridge方法不存在并且您将a List<Integer>
和a 传递MyComparator
给此函数,则标记的行的调用IMPORTANT
将失败,因为MyComparator
没有调用的方法compare
需要两个Object
s ...只有一个需要两个Integer
s.
下面的常见问题是一个很好的阅读.
小智 6
如果您想了解为什么需要桥接方法,您最好了解没有它会发生什么。假设没有桥接方法。
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);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,擦除后,方法set
inA
变为了,public void set(Object newVal)
因为 Type parameter 没有限制T
。有类没有方法B
的签名,其中相同set
的A
。所以没有覆盖。因此,当这样的事情发生时:
A a=new B();
a.set("Hello World!");
Run Code Online (Sandbox Code Playgroud)
多态在这里不起作用。请记住,您需要在子类中覆盖父类的方法,以便您可以使用父类 var 来触发多态。
桥接方法的作用是使用来自同名但签名不同的方法的所有信息静默覆盖父类中的方法。在桥接方法的帮助下,多态起作用了。尽管从表面上看,您使用不同签名的方法覆盖了父类方法。
归档时间: |
|
查看次数: |
15230 次 |
最近记录: |