为什么java不支持动态变量调度

时间:2013-07-07 09:35:23

标签: java inheritance

如果标题错误,请原谅。有两个类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
    }
}

请告诉我这种行为的原因。提前谢谢....

5 个答案:

答案 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
    }
}

因此,如果你要封装你的字段,你会有预期的行为。