Java中成员变量的隐藏
前几天看一篇文章,里面提到了成员变量的"重写"问题,刚看到的时候我非常疑惑,难道成员变量不是和方法一样的重写机制吗?结果当然是啪啪打脸。这个知识点确实是我的知识误区,因为我记得当初学Java的时候讲多态,主要提到了方法的重写体现了Java的多态性,没有提到过成员变量在继承中是如何变化的。(也许任老师讲过,我忘了。。)。平时开发时,在子类声明同名的成员变量,看到的效果是会覆盖掉父类的变量,下意识地就会认为成员变量和方法是一样的,会覆盖父类的成员变量。但其实不是这样的,我们看一个栗子。(PS:如果知道这个知识点就不需要看了)
public class Test {
public static void main(String[] args) {
Child c1 = new Child();
System.out.println((c1).s);
System.out.println((c1).fuc());
Parent c2 = new Child();
System.out.println(c2.s);
System.out.println(c2.fuc());
}
}
class Parent{
String s = "Parent";
String fuc() {
return "this is parent";
}
}
class Child extends Parent {
String s = "Child";
@Override
String fuc() {
return "this is child";
}
}
看这段代码的输出结果是什么?
Child
this is child
Child
this is child
我的第一反应是上面这个,似乎没有毛病,但其实正确答案是酱紫
Child
this is child
Parent
this is child
很难受,只是使用了父类的引用,为毛被覆盖的成员变量又冒出来了?
因为这货根本不是被"重写"或是"覆盖"了,而是被"隐藏"了起来。
这也是Java面向对象的一个概念,叫做Field Hiding。其实在重写的定义中只提到了方法,并没有提到成员变量
在Java的子类与父类中有两个名称、参数列表都相同的方法的情况。由于他们具有相同的方法签名,所以子类中的新方法将覆盖父类中原有的方法。
在子类中声明了和父类同名的成员变量,那么不管类型如何,父类中的成员变量会被隐藏。那么要想使用父类中的成员变量应该怎么做呢?只能使用父类的引用来获取父类的成员变量。这和方法的重写是有区别的,比如上面的使用父类引用的输出:
Parent
this is child
显然,输出的是父类的成员变量和子类的方法,那么为什么会这样呢?在这里要理解多态的概念,子类重写了父类的方法,发生了多态,但成员变量只是隐藏,并没有重写。所以父类的引用调用方法时,通过多态找到了子类的实现,但打印成员变量并没有。
成员变量和方法有一些区别,网上的大佬做了总结:
成员变量:当子父类有同名成员变量时,多态调用时,只看调用该成员变量的引用所属于的类中的成员变量。简单说:无论编译或运行,都看等号的左边就行了。
成员函数:当子父类有同名成员函数时,多态调用时,编译时看的是引用变量所属的类中的方法;运行时,看的是对象所属的类中的方法。简单说:编译看左边,运行看右边。
看到这,就会发现隐藏成员变量并不是一个知识点,从多态出发就会发现这是一个必然的事情,我还是学艺未精。。继续努力。。