繁体   English   中英

为什么标有 //1 的行打印 57 而不是 39?

[英]Why does the line marked with //1 print 57 instead of 39?

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'。 当您覆盖该方法时,您不能使用参数,它具有原始参数类的子类。 如果您在 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)' 方法)最接近的具有签名 'proc(X)' 的覆盖或原始方法,在 Y 类中找到它并执行 Y.proc(xp)。 这就是您在输出中看到“57”的原因。

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

如果你传递了一个实际的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
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类的重载方法?

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

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

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

x.proc(z)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM