zoukankan      html  css  js  c++  java
  • 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流水账公众号
  • 相关阅读:
    地址栏访问Action,后来方法执行两次
    转:Android中的Selector的用法
    转:android 自定义RadioButton样式
    Android中@id与@+id区别
    INSTALL_PARSE_FAILED_MANIFEST_MALFORMED 错误
    Supervisor
    mysql 赋予权限连接
    定时任务
    git 提交代码五部曲
    Mysql 之事物
  • 原文地址:https://www.cnblogs.com/guofu-angela/p/9111306.html
Copyright © 2011-2022 走看看