Java java学习

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

2015-07-22  本文已影响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>

本文代码下载:百度网盘

上一篇下一篇

猜你喜欢

热点阅读