public class Animal{
int n = 5;
public static void main(String[] args) {
Animal a = new Animal();
Animal ah = new Horse();
Horse h = new Horse();
System.out.println(h.n); // prints 7
System.out.println(ah.n); // prints 5
h = (Horse) ah;
System.out.println(h.n); // prints 7
}
}
class Horse extends Animal{
int n = 7;
}
为什么h.n
在h = (Horse) ah
之后仍然打印7?在赋值之后它应该指向ah
个点且n个字段指向5的同一个对象?
答案 0 :(得分:8)
首先,让我们调用类n
“Animal
”的字段Animal.n
,以避免混淆。
与方法不同,字段不受覆盖。所以在你的Horse课程中,你可能认为你用{7}覆盖了Animal.n
的值,你实际上是在声明一个名为n
的新变量(我们称之为Horse.n
以避免混淆)
实际上,您有一个名为Horse
的课程,其中包含两个字段:Animal.n
和Horse.n
。当您说“n
”时,您会得到哪个字段取决于当时变量的 static 类型。
如果您的对象的类型为Horse
,但最高为Animal
,则n
字段引用Animal.n
,其值为“5” 。因此ah.n
是“5”。
当您拥有相同的对象时,再次向下转换为Horse
,n
字段引用Horse.n
,其值为“7”。因此h.n
是“7”。
澄清:确实,h
确实指向ah
指向的同一对象 - 向下转换不会更改指向的对象。但是,静态类型确实会影响请求对象的哪个字段。
答案 1 :(得分:0)
您在Java中创建的每个对象(称为实例)都指向创建它的类。这是对象的真实类型,并且在对其进行转换时不会更改。类似地,引用对象的每个变量都具有声明的类型。这是编译器处理对象并确定允许的操作的方式。
然而,这两种类型只是松散耦合。转换对象引用仅更改声明的类型。它不会影响对象的行为方式 - 只有编译器如何处理它。