首先我们先来看一段非常简单的代码:
public class ClazzTest {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println(" s1.name : " + s1.name);
System.out.println(" s1.say : " + s1.say());
Father s2 = new Son();
System.out.println(" s2.name : " + s2.name);
System.out.println(" s2.say : " + s2.say());
}
}
class Father {
String name = "Jack";
String say() {
return "I am Father";
}
}
class Son extends Father {
String name = "Jack‘s son";
String say() {
return "I am son";
}
}
输出:
s1.name : Jack‘s son
s1.say : I am son
s2.name : Jack
s2.say : I am son
那为什么会出现这样的情况呀?就要说到java中的重载(overload)和重写(override)了。
在Java的子类与父类中有两个名称、参数列表都相同的方法的情况。
由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法。
正是因为Java在继承中有方法的重写,所以,这也体现了Java的动态多态性。
那么问题来了,成员变量在Java中能够被重写么?
在Java的重写介绍中明确的说了,重写,指的是方法。并没有提到成员变量。
通过上面的例子,其实我们也可以发现,成员变量并没有被重写。
所以,Java中,成员变量并不会被重写。因此这里就引申出了另外一个词:隐藏。
Java中成员变量的隐藏:
在Java的文档中,对隐藏域有这么一段的定义:
Within a class, a field that has the same name as a field in the superclass hides the superclass’s field,
even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name.
Instead, the field must be accessed through super.
Generally speaking, we don’t recommend hiding fields as it makes code difficult to read.
(强大的有道翻译出场,他说:)
在一个类中,子类中的成员变量如果和父类中的成员变量同名,那么即使他们类型不一样,只要名字一样。
父类中的成员变量都会被隐藏。在子类中,父类的成员变量不能被简单的用引用来访问。
而是,必须从父类的引用获得父类被隐藏的成员变量,一般来说,我们不推荐隐藏成员变量,因为这样会使代码变得难以阅读。
其实将其翻译成简短的一句话,就是说:子类不会去重写覆盖父类的成员变量,所以成员变量的访问不能像方法一样使用多态去访问。
那么问题又来了,我们又如何访问被隐藏的成员变量呢?
就是使用父类的引用来访问成员变量:
Son s1 = new Son();
System.out.println(" s1.name : " + ((Father)s1).name
输出:
s1.name : Jack