class Foo {
public int a = 3;
public void addFive() {
a += 5;
System.out.print("f ");
}
}
class Bar extends Foo {
public int a = 8;
public void addFive() {
a += 5;
System.out.print("b ");
}
}
public class TestInheritance {
public static void main(String [] args) {
// part 1
Foo f = new Bar();
f.addFive();
System.out.println(f.a);
// part 2
Bar b = new Bar();
b.addFive();
System.out.println(b.a);
}
}
,输出为:
b 3
b 13
第2部分我能理解。这里没什么好惊讶的。然而,第1部分不让我晚上睡觉。我理解为什么运行了Bar.addFive
,但是当我使用f.a
来实例化对象时,为什么第1部分Foo.a
会打印new Bar()
?对于方法而言,继承的工作方式与变量的工作方式完全不同。我在这里错过了什么来理解这个概念?我失败了什么?
答案 0 :(得分:3)
对于变量的方法,继承的工作方式看起来很不一样。
更确切地说,继承并不会使变量具有多态性。声明相同的方法时,派生类中的方法会覆盖基类中的方法。声明相同的变量时,基类中的变量将被派生类中的变量隐藏。
在您的示例中,Bar
有两个变量a
,但只有一个方法addFive()
。实质上,每个Bar
对象包含两个整数 - Foo.a
和Bar.a
。这两个是单独的变量。但是,addFive
方法是Bar
中定义的方法,因为它从addFive
覆盖(替换)Foo
。
请注意,Java允许Bar
通过调用Foo.addFive
访问super.addFive()
,但Bar
的用户缺乏此可能性。
答案 1 :(得分:2)
变量不是多态的。只有方法。
但是,如果声明protected
或public
或通过setter和getters
答案 2 :(得分:0)
Foo f = new Bar();
仅此一行意味着访问Bar中的实现和来自Foo的成员:)
因此,您将从a
获取Foo
,并从Bar
答案 3 :(得分:0)
为了理解第1部分,您需要了解静态和动态绑定之间的区别。
静态绑定在编译期间发生,private,final和static方法和变量使用静态绑定。静态绑定使用Type(Class)信息进行绑定。
基于上面的定义,当行Foo f = new Bar();得到编译后,变量a被初始化为3。
使用动态绑定解决方法,动态绑定使用Object解析绑定。 由于对象属于Class Bar(),因此执行Bar类的addFive()方法。因此输出b3