大家好,
我很惊讶地看到以下程序的输出:
class A{
int f() {return 0;}
int g() {return 3;}
}
class B extends A{
int f() {return 1;}
int g() {return f();}
}
class C extends B {
int f() {return 2;}
}
public class Test {
public static void main(String args[]){
A ref1 = new C();
B ref2 = (B)ref1;
System.out.println(ref2.g());
}
}
请帮助我解释代码。
答案 0 :(得分:2)
您正在创建C
的实例,并将其分配给ref1
类型的A
。此外,您还要声明类型为ref2
的变量B
,该变量将被赋值为ref1
。 ref1
的值仍然是C
的实例,即使您正在按类A
的类型查看。
调用ref2.g()
在变量g()
的实例上执行方法ref2
。这仍然是C
的唯一实例。在类B
上查找不会改变变量ref2
所引用实例的实现。
让我们通过方法C
扩展类int h() { return 5; }
。使用ref2
不能调用方法h()
,因为变量的类型是B
。但是h()
仍然存在于实例ref2
上。如果您将主方法扩展为
C ref3 = (C) ref2;
System.out.println(ref3.h());
这将输出5
。但是将ref2
的值分配给ref3
并调用h()
意味着ref2
和ref3
(和ref1
)的值是一样。
System.out.println(ref2 == ref3);
这将输出true
。因此,两个变量都指向同一个对象,即C
的实例。
答案 1 :(得分:0)
我将尝试逐步解释:
ref1
指向类C
的实例。ref2
指向类C
的相同实例。无论是通过显式类型转换完成的,堆中的实例仍然具有类型C
。再次:
ref2
的类型为B
; ref2
的C
。ref2.g()
时,JVM实际上尝试在类g()
中查找方法C
(因为如上所述,堆中的对象实例的类型为C
) )。由于类g()
中没有方法C
,因此JVM移至父类B
,在其中找到方法g()
,然后调用它。g()
中的方法B
会导致方法f()
。 JVM再次尝试在类C
中最初找到该方法,然后找到它并返回值2
。答案 2 :(得分:0)
此代码表示覆盖。并且在运行时重写时,jvm决定要调用的方法(也称为后期绑定)。
现在开始编写代码,class C
具有重写的方法f()
,并且在代码中,您已经键入了 A类(ref1
)以 B类并调用g()
方法,因此在运行时,jvm将调用g()
的{{1}}方法,而class B
是对ref2
指向class B
对象,因此在运行时class C
的{{1}}方法已绑定,它将调用{{1}的f()
方法}。