如果标题错误,请原谅。有两个类Test和TestChild1,其中TestChild1继承自Test。这两个类都有一个名为“a”的变量。当我尝试通过使用子类对象实例化的超类变量访问变量“a”时,它给出了在超类而不是子类中初始化的值。 以下是提出疑问的代码
class Test {
public int a = 10;
}
class TestChild1 extends Test {
public int a = 20;
}
class Main {
public static void main(String args[]) {
Test test = new TestChild1();
System.out.println(test.a); // results in 10
}
}
请告诉我这种行为的原因。提前谢谢....
答案 0 :(得分:9)
因为Java设计者决定使方法具有多态性(因此可以覆盖),而不是字段。
当您从对象引用字段时,编译器根据变量的声明的类型决定使用哪个字段,在本例中为Test
。
当您引用方法时,JVM在运行时根据对象的实际的具体类型选择要调用的方法,在这种情况下,该对象是TestChild
。
OO完全是关于状态的封装,所以你几乎不应该将字段暴露给外部。
答案 1 :(得分:2)
TestChild1类有两个具有相同名称的变量。如果您通过Test访问它们,那么您将获得第一个,从TestChild1获得第二个。
要获得预期结果,不应在派生类中声明a。相反,您应该在派生类的costructor中初始化它。
答案 2 :(得分:1)
您将对象声明为Test
,而不是子类。在编译时,这意味着您引用具有10的基类。
答案 3 :(得分:0)
因为行为与方法相关联而非与字段相关联。
因此,字段具有静态绑定(在本例中为此,因为测试的类型为Test
,值a
的值为10)。方法具有动态绑定。
因为变量a
没有定义Test
类的行为,所以根据其类型而不是按照其实例分配值。
答案 4 :(得分:0)
JB Nizet 已经说了所有内容,但我会添加此代码以便更好地理解:
class Test {
private int a = 10;
public int getA() {
return a;
}
}
class TestChild1 extends Test {
private int a = 20;
public int getA() {
return a;
}
}
class Main {
public static void main(String args[]) {
Test test = new TestChild1();
System.out.println(test.getA()); // results in 20
}
}
因此,如果你要封装你的字段,你会有预期的行为。