考虑以下非法代码: -
class WrongCode{
int i;
static int i;
}
这里,编译器说我们在同一个类中有重复的字段。
现在,请考虑同一文件中的以下类。
class Parent{
int i = 10;
}
class Child extends Parent{
static int i = 100;
}
public class Main{
public static void main(String ... aaa){
Parent ob = new Child();
System.out.println(ob.i); // This prints Parent's i
}
}
由于实际对象是Child,不应该ob是指Child's i?如果它引用了Parent的“i”,那么在某种程度上它也在其自己的类中拥有Parent的“i”以及它自己的静态“i”,这是不允许的。
儿童静态我遮盖了父母i。并且Parent的i不是静态的,那么如何使用实例直接访问它而不是className?
答案 0 :(得分:2)
i
类中有实例字段Parent
,它仍然是Child
类中的实例字段。
System.out.println(ob.i); // must be 10
答案 1 :(得分:1)
重要的是要认识到System.out.println(ob.i);
无法打印Child
的{{1}}:它只知道i
是声明的类型{{1}而不是它是用实际的ob
实例化的。因此,如果Parent
没有任何Child
,则会出现编译错误。如果父级有Parent
,则会打印出来。
我已经看到它在SO上提到通过实例访问类变量(即i
等同于i
)应该被认为是Java的一个严重的设计缺陷。我同意它有时会令人困惑。无论如何,你的父母和孩子也可以有一个非静态ob.i
,它不一定相同。上述论点应适用于推理在哪种情况下打印哪一个。
答案 2 :(得分:0)
在ob
中,static int i
的子节点永远不可见,因为ob
的类型为Parent,而不管它是如何实例化的(基类或派生类)。
这就是为什么你的值为 10 ,Parent
s i
值。
答案 3 :(得分:0)
Java允许您的类拥有自己的变量,这些变量与父变量具有相同的名称。但它不能让你随机重新定义父变量,因为这会导致其他东西破坏。它的作用......当你有一个被声明为父类的变量obj
时,即使它拥有子类的实例,obj.i
也会引用父类的i
而不是孩子的。
答案 4 :(得分:0)
当您访问类成员字段(实例变量)时,如ob.i.您将从编译时已知的类中获得结果,而不是运行时已知的结果。这就是为什么你的价值为10,这是父母的价值。
对于方法调用,它们在运行时被调度到引用指向的实际类的对象。
关于阴影这里是Java lang规范所说的:
如果类声明了一个具有特定名称的字段,那么该字段的声明将被隐藏为隐藏超类中具有相同名称的字段的任何和所有可访问声明,以及该类的超接口。
可以使用限定名称(如果它是静态的)
来访问隐藏字段您可以参考“现场声明”部分。
答案 5 :(得分:0)
实际上它是多态的,ob只能访问父类字段和...的行为。