java Java泛型 - 桥接方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5007357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Generics - Bridge method?
提问by sgokhales
Something called the "bridge method" concept related to Java Generics made me stop at a point and think over it.
与 Java 泛型相关的称为“桥接方法”的概念让我停下来思考它。
Btw, I only know that it occurs at the bytecode level and is not available for us to use.
顺便说一句,我只知道它发生在字节码级别,无法供我们使用。
But I am eager to know the concept behind the "bridge method" used by the Java compiler.
但我很想知道 Java 编译器使用的“桥接方法”背后的概念。
What exactly happens behind the scenes and why it is used?
幕后究竟发生了什么以及为什么使用它?
Any help with an example would be greatly appreciated.
对示例的任何帮助将不胜感激。
回答by Mark Peters
It's a method that allows a class extending a generic class or implementing a generic interface (with a concrete type parameter) to still be used as a raw type.
它是一种方法,允许扩展泛型类或实现泛型接口(具有具体类型参数)的类仍用作原始类型。
Imagine this:
想象一下:
public class MyComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
//
}
}
This can't be used in its raw form, passing two Object
s to compare, because the types are compiled in to the compare method (contrary to what would happen were it a generic type parameter T, where the type would be erased). So instead, behind the scenes, the compiler adds a "bridge method", which looks something like this (were it Java source):
这不能以其原始形式使用,传递两个Object
s 进行比较,因为类型被编译到 compare 方法中(与泛型类型参数 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);
}
}
The compiler protects access to the bridge method, enforcing that explicit calls directly to it result in a compile time error. Now the class can be used in its raw form as well:
编译器保护对桥接方法的访问,强制直接对其进行显式调用会导致编译时错误。现在该类也可以以其原始形式使用:
Object a = 5;
Object b = 6;
Comparator rawComp = new MyComparator();
int comp = rawComp.compare(a, b);
Why else is it needed?
为什么还需要它?
In addition to adding support for explicit use of raw types (which is mainly for backwards compatability) bridge methods are also required to support type erasure. With type erasure, a method like this:
除了添加对显式使用原始类型的支持(主要是为了向后兼容)之外,还需要桥接方法来支持类型擦除。使用类型擦除,这样的方法:
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;
}
is actually compiled into bytecode compatible with this:
实际上被编译成与此兼容的字节码:
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;
}
If the bridge method didn't exist and you passed a List<Integer>
and a MyComparator
to this function, the call at the line tagged IMPORTANT
would fail since MyComparator
would have no method called compare
that takes two Object
s...only one that takes two Integer
s.
如果桥接方法不存在并且您将 aList<Integer>
和 a传递MyComparator
给此函数,则标记行的调用IMPORTANT
将失败,因为MyComparator
不会调用compare
任何需要两个Object
s 的方法……只有一个需要两个Integer
s。
The FAQ below is a good read.
下面的常见问题是一个很好的阅读。
See Also:
也可以看看:
回答by ch48h2o
If you want to understand why you need bridge method, you better understand what happens without it. Suppose there is no bridge method.
如果您想了解为什么需要桥接方法,您最好了解没有它会发生什么。假设没有桥接方法。
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);
}
}
Notice that after erasure, method set
in A
became public void set(Object newVal)
since there is no bound on Type parameter T
. There is no method in class B
the signature of which is the same as set
in A
. So there is no override. Hence, when something like this happened:
请注意,擦除后,方法set
inA
变成了public void set(Object newVal)
因为 Type parameter 没有限制T
。有类没有方法B
的签名,其中相同set
的A
。所以没有覆盖。因此,当这样的事情发生时:
A a=new B();
a.set("Hello World!");
Polymorphism won't work here. Remember you need to override the method of parent class in child class so that you can use parent class var to trigger polymorphism.
多态在这里不起作用。请记住,您需要在子类中覆盖父类的方法,以便您可以使用父类 var 来触发多态。
What bridge method does is silently override the method in parent class with all the information from a method with the same name but a different signature. With the help of the bridge method, polymorphism worked. Though on the surface, you override the parent class method with a method of different signature.
桥接方法的作用是使用来自同名但签名不同的方法的所有信息静默覆盖父类中的方法。在桥接方法的帮助下,多态起作用了。尽管从表面上看,您使用不同签名的方法覆盖了父类方法。
回答by Happy
As indicated by this articleand this article, the key reason of the Java bridge method is Type Erasureand Polymorphism.
正如本文和本文所指出的,Java 桥接方法的关键原因是类型擦除和多态性。
Let's take the class ArrayDeque(source code) as example, it contains a clone()
method as bellow, because the class ArrayDeque
implements the Cloneable
interface so it must override the Object.clone()
method.
让我们以类ArrayDeque(源代码)为例,它包含一个clone()
方法如下,因为该类ArrayDeque
实现了Cloneable
接口,所以它必须覆盖该Object.clone()
方法。
public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable
{
public ArrayDeque<E> clone() {
....
}
}
But the problem is the return type of ArrayDeque.clone()
is ArrayDeque<E>
, and it did not match to the method signature defined in the parent Object.clone()
, and in Object.javathe return type is Object
instead.
但问题是返回类型ArrayDeque.clone()
就是ArrayDeque<E>
,它没有匹配到父定义的方法签名Object.clone()
,并在Object.java返回类型为Object
代替。
public class Object {
protected native Object clone() throws CloneNotSupportedException;
}
The return type mismatch is a problem for Polymorphism. So in the compiled result file ArrayDeque.class
, the Java compiler generated two clone()
methods, one match the signature in the source code, the other one match to the signature in the parent class Object.clone()
.
返回类型不匹配是Polymorphism 的一个问题。所以在编译结果文件中ArrayDeque.class
,Java编译器生成了两种clone()
方法,一种匹配源代码中的签名,另一种匹配父类中的签名Object.clone()
。
- clone()method returns
ArrayDeque<E>
, which is generated based on the corresponding source code - clone()method returns
Object
, which is generated based onObject.clone()
. This method is doing nothing but calling the otherclone()
method.And, this method is tagged as ACC_BRIDGE, which indicates this method is generated by the compiler for the Bridge purpose.
- clone()方法返回
ArrayDeque<E>
,根据对应的源码生成 - clone()方法返回
Object
基于Object.clone()
. 这个方法除了调用另一个clone()
方法什么都不做。并且,此方法被标记为ACC_BRIDGE,这表明此方法是由编译器为 Bridge 目的生成的。
回答by Callistus
It's insteresting to note that the compiler infersthat MyComparator
's method:
有趣的是,编译器会推断出该MyComparator
方法:
public int compare(Integer a, Integer b) {/* code */}
is trying to override Comparator<T>
's
正在尝试覆盖Comparator<T>
's
public int compare(T a, T b);
from the declared type Comparator<Integer>
. Otherwise, MyComparator
's compare
would be treated by the compiler as an additional (overloading), and not overridding, method. And as such, would have no bridge method created for it.
从声明的类型Comparator<Integer>
。否则,MyComparator
'scompare
将被编译器视为附加(重载)而不是覆盖方法。因此,不会为其创建桥接方法。