我正在检查一些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,我的问题是为什么?..
您需要知道Java中的后期绑定(在运行时基于实际对象查找方法体的多态性机制)仅适用于方法,而不适用于字段.
因此,如果你有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.
你有两个字段,一个隐藏,而不是替换另一个.你有Foo.a
和Bar.a
你覆盖方法改变Bar.a
但你正在查找Foo.a
添加到Peter的答案:记住成员变量是are not
多态的,所以它们不是overriden
.
即f.a
你仍然给你引用超类a
(因为f
声明的类型是Foo
),而f.addFive()
调用方法on 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
希望很清楚.