我知道字节码规范允许类具有相同签名的方法,与Java语言不同的是返回类型不同。有些语言甚至在某些情况下使用这种语言。我的问题与反思有关:
如果在一个类中我发现一个(非私有)方法的名称和参数类型与它的超类(非最终的、非私有的)相同,并且返回类型等于或是超类中该方法的返回类型的一个子类型,那么我什么时候可以假设静态调用'supermethod‘的代码总是会导致’重写(?)‘的执行。方法(自然地假设调用是对属于该类的对象进行的)?即使在编译到JVM字节码的其他语言中,或者如果涉及运行时代码生成,还是被黑客入侵的合成类(如lambda转发器)?
我的问题是注意到在Scala标准库中,Iterable[E]是如何有一个方法的:
def map[O](f :E => O) :Iterable[E]在Map[K, V]中,Iterable[(K, V)]的子类声明另一个方法:
def map[A, B](f :((K, V)) => (A, B)) :Map[A, B]实际签名比这里更复杂,但原理是相同的:擦除后,Map中的方法可以覆盖Iterable中的方法。
发布于 2021-09-08 21:25:44
重写的事实由JVM根据方法描述符的完全相等(包括参数类型和返回类型)来决定。见JVMS §5.4.5,第5.4.6条。
因此,在JVM级别上,返回Map的方法不会覆盖返回Iterable的方法。编译器通常生成一个返回Iterable的桥方法,该方法是用一个简单的委托实现的,该方法返回Map。
示例:
class A<T extends Iterable> {
T map() {
return null;
}
}
class B extends A<Collection> {
@Override
Collection map() {
return null;
}
}这里,B.map重写A.map,尽管返回类型不同。为了使这种层次结构成为可能和有效,编译器生成(在字节码级别上)另一个返回Iterable的方法Iterable。
class B extends A<java.util.Collection> {
B();
0: aload_0
1: invokespecial #1 // Method A."<init>":()V
4: return
java.util.Collection map();
0: aconst_null
1: areturn
java.lang.Iterable map();
0: aload_0
1: invokevirtual #7 // Method map:()Ljava/util/Collection;
4: areturn当在B的实例上调用虚拟方法B.map:Iterable时,总是调用方法B.map:Iterable,后者依次调用B.map:Collection。
发布于 2021-09-08 12:01:04
这最终取决于所使用的JVM指令:
invokespecial将调用该方法,而不根据当前对象的类型执行动态解析。invokevirtual将根据类进行分派。相关:当invokeSpecial存在时为什么需要invokeVirtual
所以答案是它取决于生成的字节码。
https://stackoverflow.com/questions/69102562
复制相似问题