4

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

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

4

5 回答 5

9

因为 Java 设计者决定使方法具有多态性(因此是可覆盖的),而不是字段。

当您从对象引用字段时,编译器会根据声明的变量类型(在本例中为Test.

当您引用方法时,JVM 在运行时会根据对象的实际具体类型(在本例中为TestChild.

OO 完全是关于状态的封装,因此您几乎不应该将字段暴露给外部。

于 2013-07-07T09:40:35.980 回答
2

TestChild1 类有两个同名变量。如果您通过 Test 访问它们,您将获得第一个,从 TestChild1 获得第二个。

要获得预期的结果,您不应在派生类中声明 a。相反,您应该在派生类的构造函数中对其进行初始化。

于 2013-07-07T09:41:24.100 回答
1

您将对象声明为Test,而不是子类。在编译时,这意味着您引用具有 10 个的基类。

于 2013-07-07T09:45:39.347 回答
0

因为行为与方法相关联,而不是与字段相关联。

因此,字段具有静态绑定(在这种情况下,由于 test 是 type Test,因此 valuea被赋值为 10)。而方法具有动态绑定。

由于该变量a没有定义Test类的行为,因此根据其类型而不是根据其实例为其分配值。

于 2013-07-07T09:45:13.220 回答
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
    }
}

因此,如果您封装您的字段,您将获得预期的行为。

于 2013-07-07T10:05:34.447 回答