我需要澄清Java的动态多态性。
class Foo {
int a=3;
public void display() {
System.out.println(" in foo "+a);
}
}
class Bar extends Foo {
int a=8;
public void display() {
System.out.println(" in boo "+a);
}
}
public class Tester {
public static void main(String[]args) {
Foo f = new Bar();
f.display();
System.out.println(f.a);
}
}
这里,当我使用基类引用创建子类对象时,在调用方法f.display()
时,它将输出作为in boo 8
。这是因为动态多态,它在运行时检查对象类型以调用方法。
现在打印f.a
时打印3,因为在java中无法覆盖变量,这称为隐藏。这就是为什么它显示基本变量值而不是子变量值。
现在我的问题是f是基类的引用,它指向子类对象。那么f.a
如何指向基本变量。 幕后发生了什么?引用如何指向基类?
(我知道规则,但我想知道如何/为什么?)
答案 0 :(得分:4)
我不知道这是否超出了你的学习范围,但现在就是这样。编译代码时,编译器会生成JVM执行的字节代码。
行
中Foo.a
中字段f.a
的引用
System.out.println(f.a);
编译为
getfield #6 // Field Foo.a:I
其中getfield
是a bytecode instruction
获取对象objectref的字段值,其中字段为 由常量池索引中的字段引用标识(index1 <&lt; 8 + index2)
和常量池
Constant pool:
// [...]
#6 = Fieldref #20.#24 // Foo.a:I
// [...]
因此,字节代码引用类Foo
中的字段,即变量的声明类型,而不是实例的运行时类类型。
您可以使用以下命令查看生成的字节代码
javap -c -v YourClass
答案 1 :(得分:4)
这是因为您在问题中已经说明了这一点:
变量无法在Java中重写
因此,引用f.a
在编译时静态解析,它将编译器带到Foo.a
,即3
。
答案 2 :(得分:0)
因为变量无法被覆盖,所以你从基类中提供了它的
的引用print f.a = 3
如果你这样声明
Bar f = new Bar();
现在您打印f.a
的值,它会为您提供8