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

显然,输出的是父类的成员变量和子类的方法,那么为什么会这样呢?在这里要理解多态的概念,子类重写了父类的方法,发生了多态,但成员变量只是隐藏,并没有重写。所以父类的引用调用方法时,通过多态找到了子类的实现,但打印成员变量并没有。

成员变量和方法有一些区别,网上的大佬做了总结:

成员变量:当子父类有同名成员变量时,多态调用时,只看调用该成员变量的引用所属于的类中的成员变量。简单说:无论编译或运行,都看等号的左边就行了。

成员函数:当子父类有同名成员函数时,多态调用时,编译时看的是引用变量所属的类中的方法;运行时,看的是对象所属的类中的方法。简单说:编译看左边,运行看右边。

看到这,就会发现隐藏成员变量并不是一个知识点,从多态出发就会发现这是一个必然的事情,我还是学艺未精。。继续努力。。