Java 为什么在超级上下文中调用私有方法?

Java 为什么在超级上下文中调用私有方法?,java,inheritance,Java,Inheritance,使用此代码: public abstract class A { private String runNow() { return "High"; } public abstract String cos(); static class B extends A { public String runNow() { return "Low"; } public String

使用此代码:

public abstract class A {
    private String runNow() {
        return "High";
    }

    public abstract String cos();

    static class B extends A {
        public String runNow() {
            return "Low";
        }

        public String cos() {
            return "cos from B";
        }
    }

    public static void main(String args[]) {
        A[] a = new B[] {new B(), new C()};
        for (A aa : a) {
            System.out.println(aa.runNow() + " " + aa.cos());
        }
    }
}

class C extends A.B {
    public String runNow() {
        return "Out";
    }

    public String cos() {
        return "cos from C";
    }
}
为什么调用了类
A
中的
runNow
方法而不是子类中的方法?

简短的回答是“因为
runNow()
私有的

编译此调用时,
aa.runNow()
编译器会看到
class A
具有
runNow
私有方法,并且您的代码正在调用此私有方法。由于私有方法不能被重写,编译器将调用路由到
A
runNow()
方法-它知道在该上下文中唯一存在的方法

B
C
也以相同的名称引入它们的方法,这一事实对编译器来说并不重要,因为这些方法在子类中是新的。编译器不考虑它们的重写而不破坏对类A<代码>的封装,它指定了<代码> RunNe//C>一个私有方法。

这是因为RunNoW()是A类中的一个私有方法。 私有方法未继承,因此无法重写

private String runNow(){
      return "High";
 }
并且您已经创建了一个类型为a的引用

A[] a=new B[]{new B(),new C()};

因此,将被调用以完成调用的唯一runNow()是类A,因为编译器不知道类B和C中的runNow()方法,这是因为类A中的方法
runNow()
是私有的,所以在类B和C中您不会重写它。当您调用方法
aa.runNow()
时,它直接从类A调用

尝试做一些实验,并将课堂上的方法更改为:

private String runNow2() {
    return "High";
}

public String runNow() {
    return "High";
}
同时将您的
系统.out
更改为此系统:

System.out.println(aa.runNow() + " " + aa.cos() + " " + aa.runNow2());
现在结果将如预期的那样

希望有帮助

为什么从类A调用runNow方法而不是从子类调用


private
方法不在子类中继承。因此,它们不能被覆盖。由于运行时多态性仅适用于重写的方法,因此将始终调用
A
中的
runNow
方法。将
A
中的
runNow
方法更改为
public
方法,您将获得所需的输出,因为
public
方法是继承的,并且可以被覆盖。

正如前面所说的,问题是
runNow()
是私有的。因此,它不会被重写,通过类型为
a
的引用访问它将获得
a
类的定义,而尝试通过
B
引用访问它将获得子类


不过,我想指出,这种“奇怪”行为之所以可能,是因为执行所有这些操作的方法(您的
main
方法)是在
A
内部定义的。如果您的
main
方法位于可以访问这些类的另一个类中,您将得到一个错误,表明该方法根本不可访问。如果您仔细想想,您可能会更清楚为什么
B
C
中的
runNow()
方法不会覆盖
A
中的方法。从A之外的任何对象的角度来看,根本没有
runNow()
方法-它是一个实现细节,而不是
A
契约的一部分。因此,它不能被重写,
B
C
中的
runNow()
只是新方法,当您以多态方式使用
B
C
作为
A

可能重复的方法时,您无法访问这些方法。请阅读重复的问题,了解您为什么不能重写私有方法。下次:用
@Override
注释你的方法,这样编译器就可以检查你是否真的重写了一个方法。请不要编辑你的问题来引入语法错误。你不能将你的
A[]
array
aa
@MGorgon命名请阅读