java - 如何覆盖具有默认(包)可见性范围的方法?

标签 java inheritance

我的问题是我无法理解在以下情况下方法解析是如何工作的:假设,我们有两个包,AB。有两个类,A放在A中,B放在B中。

答:

package com.eka.IO.a;
import com.eka.IO.b.B;

public class A {

    void foo() {
        System.out.println("parent");
    }

    public static void main(String... args) {
        B obj = new B();
        obj.foo();
    }

}

乙:

package com.eka.IO.b;
import com.eka.IO.a.A;

public class B extends A {

    public void foo() {
        System.out.println("child");
    }

}

上面的代码打印出“child”,这完全没问题。但是,如果我按以下方式更改主要方法:

public static void main(String... args) {
    A obj = new B();
    obj.foo();
}

代码打印“parent”,我不明白为什么。 (obj 有运行时类型 BB 有一个公共(public)方法 foo)

接下来,我将 foo 的可见性更改为公开,

public class A {

    public void foo() {

代码再次打印“child”。

据我所知,实例方法在运行时解析,使用以下原则:

  1. JVM 检查对象的运行时类。
  2. JVM寻找运行时类的方法
  3. 如果找到方法,JVM 调用它,否则移动到父运行时类。

在我的示例中,在任何三种情况下,obj 的运行时类始终是 BB 的方法foo 总是公开的。为什么在第二种情况下 JVM 调用 A 的方法?

向上: 好的答案,但有些事情对我来说还不清楚。 a) 编译器检查一个方法是否覆盖了另一个方法。 (希望,我是对的)。 b) 在 A obj = new B(); 的情况下,编译器生成以下代码:

INVOKEVIRTUAL com/eka/IO/a/A.foo ()V

b1) 如果 A 的 foo 声明时没有修饰符(包可见性),则 JVM 调用 A 的方法。 b2)如果 A 的 foo 被声明为 public,那么 JVM 调用 B 的方法。

不清楚的是为什么在第二种情况下 INVOKEVIRTUAL 实际上调用了 B.foo。它怎么知道 B 覆盖了方法?

最佳答案

该过程与您描述的略有不同。首先,Java 只会使存在于已声明类中且在当前范围内可见的方法可用。这已经在编译时完成。

在运行时,

  • JVM 检查对象的运行时类。
  • JVM 检查对象的运行时类是否覆盖了声明类的方法。
  • 如果是这样,那就是调用的方法。否则,调用声明类的方法。

现在,棘手的部分是“它是否已被覆盖”?

类不能覆盖对其不可见的方法。它可以用相同的名称和相同的参数声明一个方法,但该方法不被视为覆盖原始方法。它只是一个新方法,就像 B 中定义但 A 中没有定义的任何其他方法一样。

如果不是这样,那么你可以在作者认为不应该破坏的地方破坏 parent 的类契约(Contract),因此不允许访问它。

因此,由于该类没有覆盖该方法,您只能引用该方法,就像您能够引用 B 中声明的但不在 A 中的任何方法一样 - 只能通过 B 引用。

那么,为什么编译器不阻止您使用父类中已有的方法名称呢?

好吧,如果你得到一个包,而你所拥有的关于它的唯一信息是类契约中的内容,如它的 Javadoc 中所写,你甚至不知道该方法的存在。突然之间,您编写了一个据您所知是唯一的方法,但出现了编译错误。

没有理由这样做。您不可见的内容不应阻止您自由命名自己的方法。因此它是允许的。

但是如果您希望编译器防止您犯这样的错误,请在编写应该覆盖父级的方法时使用@Override 注释类的方法。这样,如果您试图重写不属于该类契约的方法,编译器会警告您。

关于java - 如何覆盖具有默认(包)可见性范围的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26722212/

相关文章:

c++ - 从自身的 vector 继承的类

c++ - 在 C++ 中使用多态和继承来处理一篮子水果的正确方法是什么?

c++ - 从基类向下转换时是否可以调用派生对象的虚方法?

java - 复合主键和数据截断错误

java - 使用 JCodeModel 生成 java 字节码

java - 从任何地方访问 View 而不使用静态声明

java - 如何使用spring data获取mongodb中最大聚合函数对应的值

java - 如何格式化 mySQL 日期以在 android 的日期选择器中显示?

inheritance - D 以非耦合方式向类添加功能

c++ - 如何在 C++ 中扩展和使用父类(super class)的成员?