什么是继承##
继承是指类和类之间的关系,是为了实现代码复用的一种语法。为什么代码能复用呢?因为如果类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>
本文代码下载:百度网盘
网友评论