当前位置: 首页 > 知识库问答 >
问题:

Java虚拟机规范(JVM):“5.4.5方法重写”中的错误

范振海
2023-03-14

我在2009年9月28日提交了以下bug。遗憾的是,我仍然没有得到任何回应,规范的最终版本仍然不正确。这真的是一个bug吗?如果不是,为什么不呢?如果是,我该怎么办?

包含错误的部分是5.4.5(方法重写):http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.5结合INVOKEVIRTUALopcode的描述:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.虚拟的

根据5.4.5m1可以覆盖m2,即使m1是私有的。如果手动创建. class文件或合并来自两个编译的. class,就会发生这种情况。

在我的例子中,我有类AB,其中B扩展了A。我编译了这些类,以便A包含一个名为fpublic方法,B包含一个private方法,也称为f(首先声明两种方法public,编译A.class,将A中的f声明移除,并在B中更改为private,然后编译B并使用A.class的保存版本)。

现在运行这个程序时,我当前的Oracle JVM输出A(这意味着调用A中的方法f)。根据规范,B应该是输出(意味着应该调用B中的方法f)。

编辑:实际上,B.f应该得到解决。如果调用方不是B,调用可能会失败,因为对已解析的方法进行了访问权限检查。然而,我认为方法解析部分是错误的。

我认为5.4.5中的定义应该检查m1的访问权限,而不仅仅是m2

public class A {
  public void f();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String A
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

public class B extends A {
  private void f();
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String B
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

谢谢Carsten

共有1个答案

云俊名
2023-03-14

你的问题终于解决了。Java的当前版本

如果mC与mA相同,或者以下所有条件均成立,则C类中声明的实例方法mC将覆盖A类中声明的另一个实例方法mA

  • C是a的一个子类。
  • mC与mA具有相同的名称和描述符
  • mC未标记为ACC_PRIVATE
  • 以下情况之一是正确的:
    • mA标记为ACC_PUBLIC;或被标记为ACC_保护;或者标记为既不是ACC_PUBLIC,也不是ACC_PROTECTED,也不是ACC_PRIVATE,并且A与C属于同一个运行时包。
    • mC覆盖方法m'(m'不同于mC和ma),使得m'覆盖ma

    §4.10.1.5“类型检查摘要和本机方法”中还增加了一项内容:

    私有方法和静态方法与动态方法调度是正交的,因此它们从不覆盖其他方法(§5.4.5)。

    修复不到五年,与其他一些问题相比速度很快…

 类似资料:
  • 我正在读“Java虚拟机规范第7版”,有一些东西真的让我困惑,下面是问题: 在这种情况下,使用当前帧(§2.6)恢复调用器的状态,包括其局部变量和操作数堆栈,调用器的程序计数器适当增加以跳过方法调用指令。然后在调用方法的帧中正常地继续执行,返回的值(如果有的话)推送到该帧的操作数堆栈上。 那么“跳过方法调用指令”是什么意思呢?有人能解释一下吗?非常感谢!

  • 让我们在Visual C 2010中假设以下场景: 理论上,这个小应用程序的输出应该是: 基本:非虚拟显示。 基础:虚拟显示。 基本:非虚拟显示。 派生:虚拟显示。 因为基类的显示方法不是虚拟方法,所以派生类不能重写它。正当 问题是,当我运行应用程序时,它会打印以下内容: < li >基本:非虚拟显示。 < li >基本:虚拟显示。 < li >派生:非虚拟显示。 < li >派生:虚拟显示。 所

  • 本文向大家介绍Java JVM虚拟机运行机制,包括了Java JVM虚拟机运行机制的使用技巧和注意事项,需要的朋友参考一下 一:JVM基础概念          JVM(Java虚拟机)一种用于计算设备的规范,可用不同的方式(软件或硬件)加以实现。编译虚拟机的指令集与编译微处理器的指令集非常类似。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。       

  • 本文向大家介绍Java虚拟机JVM堆栈区,包括了Java虚拟机JVM堆栈区的使用技巧和注意事项,需要的朋友参考一下 以下是了解JVM堆栈区域的一些关键点- 在创建线程期间,Java虚拟机将创建一个单独的堆栈。 JVM在此堆栈上仅执行两个操作。操作是推入(即插入)和弹出(即删除)。 当前正在执行线程时,与其关联的堆栈称为运行时堆栈。 线程完成的每个方法调用,中间计算,局部变量的分配,调用参数等都作为

  • 我已经访问了所有与我的问题相关的现有问题,但我仍然有一个问题。所有安装都正确安装。我使用的是最新的Netbeans版本。在执行程序后,我出现了以下错误:

  • 本文向大家介绍JVM虚拟机查找类文件的顺序方法,包括了JVM虚拟机查找类文件的顺序方法的使用技巧和注意事项,需要的朋友参考一下 JVM查找类文件的顺序: 在doc下使用set classpath=xxx, 如果没有配置classpath环境变量,JVM只在当前目录下查找要运行的类文件。 如果配置了classpath环境,JVM会先在classpath环境变量值的目录中查找要运行的类文件。 值的结尾