JAVA: 子类“覆盖”父类的成员变量

在实际工程中,遇到一个问题,子类需要继承父类的所有方法,但是成员变量不一样,需要覆盖父类的成员变量。

public class Base {

    private static final String gun = "ak48";
    
    public void fire(){
        System.out.println(gun);
    }
}

public class Derived extends Base {
    
    private static final String gun = "M1917";

    public static void main(String[] args) {
        new Derived().fire();
    }
}

我们希望开火的时候用M1917,而真正用的是ak48,那怎么才能不重新建一个基站就能直接用M1917呢?

Java本身是不提供覆盖父类的成员变量的,为什么呢?

答:实际上,即使子类声明了与父类完全一样的成员变量,也不会覆盖掉父类的成员变量。而是在子类实例化时,会同时定义两个成员变量,子类也可以同时访问到这两个成员变量,但父类不能访问到子类的成员变量(父类不知道子类的存在)。而具体在方法中使用成员变量时,究竟使用的是父类还是子类的成员变量,则由方法所在的类决定;即,方法在父类中定义和执行,则使用父类的成员变量,方法在子类中定义(包括覆盖父类方法)和执行,则使用子类的成员变量。

但是我们实际中就有这种需求,有几种途径可以解决这个问题:

1.提供get方法

public class Base {

    private String gun = "ak48";

    public String getGun() {
        return gun;
    }

    public void setGun(String gun) {
        this.gun = gun;
    }

    public void fire(){
        System.out.println(getGun());
    }
}

public class Derived extends Base {

    private String gun = "M1917";

    @Override
    public String getGun() {
        return gun;
    }

    @Override
    public void setGun(String gun) {
        this.gun = gun;
    }

    public static void main(String[] args) {
        new Derived().fire();
    }
}

原理:父类的 fire()开火函数调用的实际上是子类重写的getGun()方法,拿的是子类的成员变量。但实际上还是有二个成员变量存在。

2.通过修改父类成员变量

public class Base {

    protected String gun = "ak48";
    
    public void fire(){
        System.out.println(gun);
    }
}

public class Derived extends Base {

    private String gun = "M1917";

    Derived(){
        super.gun = gun;
    }

    public static void main(String[] args) {
        new Derived().fire();
    }
}

输出:M1917

这个就是利用super在子类构造函数中初始化父类的成员变量

3.static代码块

public class Base {

    protected static String gun = "ak48";

    public void fire(){
        System.out.println(gun);
    }
}

public class Derived extends Base {

    static {
        gun = "M1917";
    }

    public static void main(String[] args) {
        new Derived().fire();
    }
}

static块会在类初始化而不是实例化时被执行,而父类中的static成员变量会在子类static块执行前就定义完成,所以子类初始化时会修改父类的成员变量值,子类实例化时自然得到的父类成员变量值也是修改过的,这样完成了“覆盖”。

static块恰恰是利用了JAVA会无条件执行staitc块这一特性,达到了这个目的。这种方法说坏处的话,估计就是成员变量必须是static了。

文章参考来源:https://www.polarxiong.com/archives/JAVA-%E5%AD%90%E7%B1%BB-%E8%A6%86%E7%9B%96-%E7%88%B6%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F.html

欢迎关注Java流水账公众号
原文地址:https://www.cnblogs.com/guofu-angela/p/9111306.html