公共属性和继承Java

时间:2013-12-02 21:04:30

标签: java

我正在检查一些Java练习,但我对这个练习感到困惑:

我们有一个具有这种结构的Foo类:

public class Foo {
    public int a = 3;

    public void addFive() {
        a += 5;
    }
}

继承自Foo的Bar类:

public class Bar extends Foo {
    public int a = 8;

    public void addFive() {
        a += 5;
    }
}

还有一个测试类:

public class Test {

    public static void main(String[] args) {
        Foo f = new Bar();
        f.addFive();
        System.out.println(f.a);
    }
}

我认为输出是13,但它是3,我的问题是为什么?..

5 个答案:

答案 0 :(得分:7)

添加到Peter的答案:请记住成员变量are not是多态的,因此它们不是overriden
f.a仍然提供超级类a的引用(因为f的声明类型为Foo)而f.addFive()调用Bar上的方法, (因为f的运行时类型为Bar);

所以,例如

Bar b = new Bar();
Foo f = b;
f.addFive();
System.out.println(f.a); // prints 3
System.out.println(b.a); // prints 13 as you have expected

希望很清楚。

答案 1 :(得分:5)

您有两个字段,一个隐藏,而不是替换另一个。您有Foo.aBar.a您覆盖的方法会改变Bar.a,但您正在查找Foo.a

答案 2 :(得分:5)

你需要知道在Java late-binding(在运行时基于实际对象找到方法体的多态机制)仅对方法工作,而不是对字段工作。

因此,如果你有基类型Foo的引用,它包含从Foo派生的类型的对象,就像在我们的案例中Bar

Foo f = new Bar();

然后使用f.field,您将使用Foo类中的字段(此处不存在多态行为)。
但是如果你使用f.someMethod(),那么感谢运行时的后期绑定,Java将从Bar类中找到并执行此方法的代码(因为f拥有Bar对象的内容) 。

所以在你的代码中

Foo f = new Bar();//you are creating reference of type Foo to instance of Bar
f.addFive();//body of this method will increment `a` declared in `Bar`
System.out.println(f.a);//here you are using `a` declared in Foo.

如果您使用a类型的引用,则可以从Bar类获取值Bar

System.out.println(((Bar)f).a);//prints 13.

答案 3 :(得分:0)

因为您正在将Bar对象初始化为Foo。这里有两个选择,要么将其初始化为直接Bar对象,要么将getter添加到直接连接到该属性的Bar对象。

Bar bar = new Bar();
bar.a;

public class Bar extends Foo{
    public int a = 8;

    public int getA() {
        return a;
    }

    public void addFive(){
        int a += 5;
    }
}

bar.getA();

答案 4 :(得分:0)

Bar#addFive()方法中,您声明了本地int a。对此本地int a的更改不会影响班级成员int a。由于fFoo,因此a的值在这种情况下为3

此外,您无需在addFive()课程中重新声明Bar方法,因为与Foo#addFive()方法没有区别。

编辑:奇怪的是,您最初发布的代码已更改,int a现在不再是本地代码。您使用的实际代码是什么?