美文网首页Java java学习
面向对象三大特性(二):继承

面向对象三大特性(二):继承

作者: 许宏川 | 来源:发表于2015-07-22 03:58 被阅读125次

    什么是继承##

    继承是指类和类之间的关系,是为了实现代码复用的一种语法。为什么代码能复用呢?因为如果类B继承了类A,那么类B拥有类A的部分属性和方法而不需要再写一遍。这里说部分属性和方法是因为用private修饰的属性和方法子类无法访问。
    继承因为很像现实中的父子关系,儿子拥有父亲的部分特征,所以叫继承。被继承的类叫父类或者超类,继承的类叫子类或者派生类。但是用父子关系比喻继承其实也不是很恰当,因为继承双方通常是范围关系,父类的范围比子类范围广,子类通常是父类的一种细分。例如蔬菜和萝卜的关系,电脑和笔记本电脑的关系,操作系统和Windows的关系,Windows系统和Windows 10的关系。

    继承使用的关键字是extends,如果要让类B 继承 类A,语法是这样的:

    public class B extends A {
    
    }
    

    我们继续封装 这篇文章的代码上继续修改。在pc包下创建两个类DeskTop和LapTop继承PC类。
    因为台式机处理器、内存、显卡、硬盘和屏幕(显示器)都是可以替换的,所以为这些属性都添加了setter()。

    public class DeskTop extends PC {
    
        public void setProcessor(String processor) {
            this.processor = processor;
        }
    
        public void setMemory(int memory) {
            this.memory = memory;
        }
    
        public void setVideoCard(String videoCard) {
            this.videoCard = videoCard;
        }
    
        public void setHardDrive(int hardDrive) {
            this.hardDrive = hardDrive;
        }
    
        public void setDisplay(int display) {
            this.display = display;
        }
    
    }
    

    因为笔记本电脑通常只能替换内存和硬盘(大部分笔记本是不要钻牛角尖)所以只添加内存和硬盘这两个属性的setter()。

    public class LapTop extends PC {
    
        public void setMemory(int memory) {
            this.memory = memory;
        }
    
        public void setHardDrive(int hardDrive) {
            this.hardDrive = hardDrive;
        }
    
    }
    

    其实这个时候所有setter()都报错了,因为PC的属性是private的,除了PC本身其它类根本无法访问,子类也不行。所以像<code>this.memory = memory;</code>这样是不行的。这个时候就要解释下上篇文章还剩下的protected这个访问修饰符了。它和继承息息相关。使用protected修饰的属性和方法除了本类外,子类也能访问。因为private是子类无法访问的,所以我们要把PC类的属性都改为protected的。事实上这里使用default和public子类也能访问,之所以使用protected因为安全进行封装,访问权限在够用的前提下越小越好。

        protected String processor; //处理器
        protected int memory; //内存
        protected String videoCard; //显卡
        protected int hardDrive; //硬盘
        protected int display; //屏幕
        protected com.xuhongchuan.os.OS OS; //操作系统
    

    这样就不会报错了,而且DeskTop和LapTop根本没有写任何属性却能通过this调出属性说明已经从父类PC里继承下来了。

    以上是关于属性的继承,接下来说说方法的继承。
    方法的继承分两部分讲,一部分是构造方法,另一部分是普通的方法。但是不管是构造方法还是普通方法,所有方法都和属性一样只要不是父类里用private修饰都会被子类继承下来。另外如果子类又写了一个父类已经存在的方法,也就是方法名和参数列表相同,但是具体实现不同。这个行为称为方法的重写。注意和方法重载别搞混了,方法重载是同一个方法名但参数列表不同。

    首先说说构造方法。在继承里构造方法有一条非常重要的规则:

    • 实例化子类时会先调用父类的构造方法再调用子类的构造方法,如果在子类的构造方法里不指明调用哪个父类的构造方法,默认调用无参构造方法。

    举例子,我们在PC类添加一个带参数的构造方法:

        //带参构造方法
        public PC(String processor, int memory, String videoCard, int hardDrive, int display) {
            this.processor = processor;
            this.memory = memory;
            this.videoCard = videoCard;
            this.hardDrive = hardDrive;
            this.display = display;
    
            System.out.println("一台新的电脑诞生了。");
            System.out.println("处理器为:" + processor + ",内存大小为:" + memory + ",显卡为:" + videoCard + ",硬盘大小为:" + hardDrive + ",显示器大小为:" +display);
        }
    

    然后DeskTop也添加分别添加无参数和有参数的构造方法

        public DeskTop() {
            System.out.println("这是一台台式机");
        }
    
        public DeskTop(String processor, int memory, String videoCard, int hardDrive, int display) {
            System.out.println("这是一台台式机");
        }
    

    测试代码:

        DeskTop deskTop = new DeskTop();
        DeskTop deskTop2 = new DeskTop("I7-4790K", 16, "GTX970", 2000, 24);
    

    <pre>
    一台新的电脑诞生了。
    这是一台台式机
    一台新的电脑诞生了。
    这是一台台式机
    </pre>

    从运行结果可以看出:子类实例化时首先会调用父类的构造方法,然后再调用子类的构造方法。而且无论子类调用的是无参还是有参的构造方法,默认都会调用父类的无参构造方法。
    那怎么调用父类的有参构造方法呢?
    答案是使用super关键字:

    super关键字##

    super关键字和this关键字差一样的用法,只是this代表本类和super代表父类。可以像使用this一样使用super和小圆点来调用父类的属性和方法。而super()代表的是父类的无参构造方法,super(参数列表)代表的是父类的有参构造方法。

    基于此我们改下DeskTop的有参构造方法。

        public DeskTop(String processor, int memory, String videoCard, int hardDrive, int display) {
            super(processor, memory, videoCard, hardDrive,display);
            System.out.println("这是一台台式机");
        }
    

    这样就会调用父类的有参数构造方法里,注意参数列表要一一对应。

    我们在运行一下测试代码,运行结果为:

    <pre>
    一台新的电脑诞生了。
    这是一台台式机
    一台新的电脑诞生了。
    处理器为:I7-4790K,内存大小为:16,显卡为:GTX970,硬盘大小为:2000,显示器大小为:24
    这是一台台式机
    </pre>

    以上是关于构造方法的继承,接下来说说普通方法。其实和构造方法的继承的区别就是,调用子类的普通方法不会再先调用父类的对应方法。

    我们使用OS类来做实验,首先把OS类的属性也改为protected的。

        protected String name; //系统名称
        protected String language; //系统语言
        protected int timeZone; //时区
    

    然后在os包下创建Windows类继承OS类。

    public class Windows extends OS {
    
        public Windows() {
            super();
            this.name = "Windows";
        }
    
        @Override
        public void logOff() {
            System.out.println("正在注销。。。");
            System.out.println("10秒后");
            System.out.println("注销成功");
        }
    
    }
    

    测试代码:

        Windows win = new Windows();
        win.logOff();
    

    运行结果:
    <pre>
    正在注销。。。
    10秒后
    注销成功
    </pre>

    从结果可以看出,调用子类的普通方法并不会调用父类对应的方法,因为父类的logOff()方法是会调用exitApps()也就是会输出:关闭所有正在运行的程序。。。
    如果子类重写的方法要调用父类的方法,也就是要在父类的基础上追加内容还是使用super关键字。
    在Windows的logOff()最前面添加一句:

    super.logOff();
    

    再运行一遍:

    <pre>
    关闭所有正在运行的程序。。。
    正在注销。。。
    10秒后
    注销成功
    </pre>

    本文代码下载:百度网盘

    相关文章

      网友评论

        本文标题:面向对象三大特性(二):继承

        本文链接:https://www.haomeiwen.com/subject/cehuqttx.html