【问题标题】:Why does the line marked with //1 print 57 instead of 39?为什么标有 //1 的行打印的是 57 而不是 39?
【发布时间】:2020-02-17 19:42:59
【问题描述】:
class X {
    protected int v = 0;

    public X() {
        v += 10;
    }

    public void proc(X p) {
        System.out.println(43);
    }
}

class Y extends X {
    public Y() {
        v += 5;
    }

    public void proc(X p) {
        System.out.println(57);
    }

    public int getV() {
        return v;
    }
}

class Z extends Y {
    public Z() {
        v += 9;
    }

    public void proc(Z p) {
        System.out.println(39);
    }
}

class Main {
    public static void main(String[] args) {
        X x = new Z();
        Y y = new Z();
        Z z = new Z();
        x.proc(z);// 1
        System.out.println(y.getV());
    }
}

据我所知,方法 proc() 在 X 类型的对象上调用,该对象“持有”类型 Z,并且在运行时 JVM 检查对象的类型并使用来自 Y 的 proc() 方法覆盖该方法。但是方法参数是Z类型的,为什么不调用Z类的重载方法呢?

【问题讨论】:

  • Z 的 proc 版本不是 super 的 proc 的覆盖 - 尝试在 procY 版本和 procZ 版本和Z 版本编译失败。 “错误:方法没有覆盖或实现超类型中的方法”......“子类中的实例方法具有相同的签名(名称,加上其参数的数量和类型)和返回类型作为实例方法超类覆盖超类的方法。”这就是调度在 Y 版本停止的原因。

标签: java inheritance polymorphism overriding overloading


【解决方案1】:

这是因为您没有覆盖 Z 类中的方法 'proc'。当您覆盖该方法时,您不能使用具有原始参数类的子类的参数。如果你在 Z.proc(Z p) 上添加@Override,你的代码将不会被编译。

假设这是可能的,那么你可以在执行 Z.proc(Z p) 的过程中使用 Z 类中的一些方法。

class Z extends Y {
    public Z() {
        v += 9;
    }

    public void proc(Z p) {
        someActions();
        System.out.println(39);
    }

    private void someActions() {
        System.out.println("Some actions");
    }

}

现在当你执行时

X x = new Z();
x.proc(new X());

应该发生什么? X 类中没有“someActions”方法。它应该如何工作?这就是 Z.proc(Z p) 不覆盖 X.proc(X p) 的原因。 Z 类,有两种不同的方法:Z.proc(Z p) 和 Y.proc(X p)。

当你打电话时

X x = new Z();
x.proc(new Z());

JVM 寻找与 Z 类(因为 X 类具有 'proc(X)' 方法)最接近的覆盖或原始方法,并在 Y 类中找到它并执行 Y.proc(x p)。这就是您在输出中看到“57”的原因。

【讨论】:

    【解决方案2】:

    因为您将X 传递给proc,所以procY 占上风。

    如果你传递一个实际的Z,声明为Z,它会打印39。

    Z x = new Z();
    X y = new Z();
    Z z = new Z();
    
    
    z.proc(x); // prints 39
    z.proc(y); // prints 57
    

    【讨论】:

      【解决方案3】:

      只是为了详细说明 Federico 的答案。 实际上,“x”对象是指向内存中“Z”实例的“X”变量。 “Z”实例只有两种方法:

      void proc(Z p)
      void proc(X p)
      

      但运行时只知道在“X”类中实现的第二个方法,并且它被“Y”类中实现的方法覆盖。 所以,当你打电话时:

      x.proc(z)
      

      运行时只知道第二个方法并调用它,执行被覆盖的方法。

      【讨论】:

        猜你喜欢
        • 2017-08-29
        • 1970-01-01
        • 2016-10-17
        • 1970-01-01
        • 2021-06-27
        • 2019-08-02
        • 1970-01-01
        • 1970-01-01
        • 2020-09-16
        相关资源
        最近更新 更多