4

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

包含错误的部分是5.4.5(方法覆盖):http ://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.5结合描述INVOKEVIRTUAL操作码:http ://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokevirtual

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

在我的示例中,我有课程AB使用B extends A. 我编译了这些类,使其A包含一个public名为的方法,fB包含一个private方法,也称为f(首先声明两个方法public,编译,复制A.class到安全的地方,删除 in 的声明fA更改为privatein B,然后编译B并使用保存的版本A.class)。

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

编辑:实际上,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
}

谢谢,卡斯滕

4

1 回答 1

1

你的问题终于解决了。Java 8 JVM 规范的当前版本包含所需的说明:

5.4.5 覆盖

在类 C 中声明的实例方法 m C会覆盖在类 A 中声明的另一个实例方法 m A ,前提是 m C与 m A相同,或者以下所有条件都为真:

  • C 是 A 的子类。
  • m C与 m A具有相同的名称和描述符。
  • m C未标记为 ACC_PRIVATE。
  • 以下情况之一为真:
    • m A被标记为 ACC_PUBLIC;或标记为 ACC_PROTECTED;or 既不标记 ACC_PUBLIC 也不标记 ACC_PROTECTED 也不标记 ACC_PRIVATE 并且 A 属于与 C 相同的运行时包。
    • m C覆盖方法 m' (m' 不同于 m C和 m A),因此 m' 覆盖 m A

§4.10.1.5 “类型检查抽象和本机方法”中还有另一个补充:

私有方法和静态方法与动态方法分派是正交的,因此它们永远不会覆盖其他方法(第 5.4.5 节)。

不到五年的时间来修复,与其他一些问题相比,这速度很快……</p>

于 2014-02-13T21:04:23.280 回答