java - 在 Java 字节码/类格式中,是什么决定了一个方法是否覆盖另一个方法?
问题描述
我知道字节码规范允许类具有具有相同签名的方法,仅在返回类型上有所不同,这与 Java 语言不同。有些语言甚至在某些情况下使用它。我的问题与反思有关:
如果在一个类中我找到一个(非私有)方法,其名称和参数类型与其超类(非最终,非私有)相同,并且返回类型等于或是所述返回类型的子类型超类中的方法,我什么时候可以假设静态调用“超方法”的代码将始终导致执行“覆盖(?)”方法(自然假设调用是在该类的对象上进行的)?即使在其他语言编译为 JVM 字节码的情况下,或者如果涉及运行时代码生成,或者在像 lambda 转发器这样的被黑客入侵的合成类中?
我的问题是从注意到 Scala 标准库中的Iterable[E]
一个方法引起的:
def map[O](f :E => O) :Iterable[E]
而 aMap[K, V]
的子类Iterable[(K, V)]
声明了另一个方法:
def map[A, B](f :((K, V)) => (A, B)) :Map[A, B]
实际的签名比这里复杂,但原理是一样的:擦除后,in 的方法Map
可以覆盖 in 的方法Iterable
。
解决方案
覆盖的事实由 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
,即使返回类型不同。为了使这种层次结构成为可能和有效,编译器(在字节码级别)生成另一个B.map
返回的方法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
当A.map
在 的实例上调用虚拟方法时,总是会调用B
一个方法,而该方法又会调用.B.map:Iterable
B.map:Collection
推荐阅读
- java - java - 如何添加 - 字符串数字的第三位之后
- security - 如何阻止欺诈信用卡/借记卡?
- php - Magento 2 商店视图中的区域设置错误(翻译错误)
- java - “java.lang.NullPointerException”异常。在另一部手机上尝试应用程序后无法评估 android.os.Bundle.toString()'
- python - 使用 Python 读取堆叠的 JSON 文件
- freefem++ - 如何在 FreeFem++ 中直接更改我的 FE 空间的边界值?
- php - 如何在二十五主题的左右浮动中添加垂直广告横幅?
- amazon-web-services - 来自 Openstack 客户端的 AWS Openstack Connectfailure
- php - 卡在 laravel 查询中
- android-studio - 使用配置 gradle 重复值资源 'attr/highlightColor'