为什么标有 //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 类型的对象上调用的,而 "holds" 是 Z 类型,并且在运行时 JVM 检查对象的类型并使用 proc() 覆盖方法method from Y.But 方法参数是Z类型,为什么不调用Z class的重载方法?
因为您要将 X
传递给 proc
,所以 class 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
发生这种情况是因为您没有覆盖 Z class 中的方法 'proc'。重写方法时,不能使用参数,它有原始参数 class 的子 class。如果您在 Z.proc(Z p) 上添加 @Override,您的代码将不会被编译。
让我们想象一下这是可能的,然后你可以在执行过程中使用 Z class 中的一些方法 Z.proc(Z p).
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());
会发生什么? Xclass中没有'someActions'方法。它应该如何运作?这就是 Z.proc(Z p) 不覆盖 X.proc(X p) 的原因。 Class Z,有两种不同的方法:Z.proc(Z p) 和 Y.proc(X p)。
当你打电话给
X x = new Z();
x.proc(new Z());
JVM 寻找最接近 Z 'proc(X)' 到 Z class 的重写或原始方法(因为 X class 有 'proc(X)' 方法)在 Y class 并执行 Y.proc(x p)。这就是您在输出中看到“57”的原因。
只是为了详细说明 Federico 的回答。
"x" 对象实际上是一个指向内存中 "Z" 实例的 "X" 变量。 "Z"实例只有两个方法:
void proc(Z p)
void proc(X p)
但是运行时只知道在 "X" class 中实现的第二个方法,它被 "Y" class 中实现的方法覆盖。
所以,当你打电话时:
x.proc(z)
运行时只知道第二个方法并调用它,执行被覆盖的方法。
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 类型的对象上调用的,而 "holds" 是 Z 类型,并且在运行时 JVM 检查对象的类型并使用 proc() 覆盖方法method from Y.But 方法参数是Z类型,为什么不调用Z class的重载方法?
因为您要将 X
传递给 proc
,所以 class 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
发生这种情况是因为您没有覆盖 Z class 中的方法 'proc'。重写方法时,不能使用参数,它有原始参数 class 的子 class。如果您在 Z.proc(Z p) 上添加 @Override,您的代码将不会被编译。
让我们想象一下这是可能的,然后你可以在执行过程中使用 Z class 中的一些方法 Z.proc(Z p).
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());
会发生什么? Xclass中没有'someActions'方法。它应该如何运作?这就是 Z.proc(Z p) 不覆盖 X.proc(X p) 的原因。 Class Z,有两种不同的方法:Z.proc(Z p) 和 Y.proc(X p)。
当你打电话给
X x = new Z();
x.proc(new Z());
JVM 寻找最接近 Z 'proc(X)' 到 Z class 的重写或原始方法(因为 X class 有 'proc(X)' 方法)在 Y class 并执行 Y.proc(x p)。这就是您在输出中看到“57”的原因。
只是为了详细说明 Federico 的回答。 "x" 对象实际上是一个指向内存中 "Z" 实例的 "X" 变量。 "Z"实例只有两个方法:
void proc(Z p)
void proc(X p)
但是运行时只知道在 "X" class 中实现的第二个方法,它被 "Y" class 中实现的方法覆盖。 所以,当你打电话时:
x.proc(z)
运行时只知道第二个方法并调用它,执行被覆盖的方法。