收听以下代码(source):
class Parent {
Integer a = 1;
static Integer b = 2;
}
class Child extends Parent {
static Integer a = 41;
Integer b = 42;
}
public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Parent yo = new Child();
System.out.format("%d %d %d %d %d %d ",
parent.a,
parent.b,
child.a,
child.b,
yo.a,
yo.b);
}
}
为什么分别是yo.a
和yo.b
1和2的结果?我很困惑,因为yo
指向一个Child
对象,它会产生41和2作为结果,因为在Parent
中,a是非静态的,因此子类的版本为{将打印{1}}而不是超类版本。
答案 0 :(得分:2)
变量(字段)未被覆盖,既不是实例变量也不是类变量。
对象始终具有来自所有超类的所有实例变量。一个类只有它自己定义的静态变量,尽管它也可以访问超类(和接口)变量(如果不是私有的)。
如果重新定义子类中的变量,则会隐藏原始变量,即无法直接访问它。它仍然存在。
可访问哪个变量只取决于用于访问它的(编译时)类型,而不取决于具体对象的类。
答案 1 :(得分:1)
字段没有动态绑定,字段的所有绑定都在编译时完成。这就是为什么,它是父类的打印字段而不是孩子。而且,静态修饰符不会改变任何东西,你可以删除所有静态修饰符,也可以得到相同的结果..
您应该记住,只有实例方法是用Java语言动态绑定的。
答案 2 :(得分:1)
根据编译时类型,这个修改过的示例可能有助于澄清关于哪些字段被看到或隐藏的决定:
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
Parent yo = new Child();
System.out.println(parent.a + " " + parent.b);
System.out.println(child.a + " " + child.b);
// you said it's a Parent
System.out.println(yo.a + " " + yo.b);
// but now you're saying it's a child
System.out.println(((Child)yo).a + " " + ((Child)yo).b);
// you said Child, but now you're saying it's a Parent
System.out.println(((Parent)child).a + " " + ((Parent)child).b);
}
给出输出:
1 2
41 42
1 2
41 42
1 2
编译器根据您提供的信息做出决定。
答案 3 :(得分:0)
类a
对象中没有实例变量Child
。或者,更确切地说,a
个对象中唯一的实例变量Child
是从Parent
继承的实例变量Child
; class a
没有定义自己的名为{{1}}的实例变量。
答案 4 :(得分:0)
类有字段。实例字段不能被覆盖,只能隐藏在子类中。无法覆盖或隐藏局部变量。静态字段和方法绑定到类,并且尝试使用实例变量会产生误导,因为忽略了实例变量。
e.g。
Parent yo = null;
System.out.println(yo.a); // prints 1
顺便说一句:除非你真的需要一个整数,否则最好使用int
而不是Integer
。