一、引入
相同特征产生代码冗余,有如下俩个类(Java
学生类和UI
学生类)
// JavaStudent.java
public class JavaStudent {
private String number; // 学号
private String name; // 姓名
private int age; // 年龄
private String classes; // 班级
private String project; // 项目
// 考试
public void exam(){
System.out.println("学员考试");
}
// 登录
public boolean login(String stuNo, String pwd){
System.out.println("使用学号和密码登录");
return true;
}
//...
}
// UIStudent.java
public class UIStudent {
private String number; // 学号
private String name; // 姓名
private int age; // 年龄
private String classes; // 班级
private String opus; // 作品
// 考试
public void exam(){
System.out.println("学员考试");
}
// 登录
public boolean login(String stuNo, String pwd){
System.out.println("使用学号和密码登录");
return true;
}
//...
}
经过观察俩个类可以发现,它们都有一些相同特征(相同的属性、相同的方法),比如相同的属性有学号、姓名、年龄、班级;相同的方法有考试和登录。
针对上述发现问题,就有如下解决方案,就是把相同的属性和行为抽取出来,就可以降低重复代码的书写。抽取出来的共性代码单独封装到一个类中
二、概述
- 继承是将多个类的相同属性和行为抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的这个类即可使用这些属性和行为
- 多个称为子类(派生类),单独的这个类称为父类(基类、超类)
三、使用方式
当多个类中有相同的代码(属性、行为)时,把相同的代码抽取出来,封装到了一个单独的类中,这样做的好处就是提高代码的复用性,但是这样做就面临一个问题,就是单独封装出来的类和之前被抽取代码的类,怎么建立联系(允许使用单独封装类中的成员)。接下来就解决这个问题
-
使用继承需要在2个或者多个类之间
-
Java
使用关键字extends
表示继承 -
语法格式
public class 子类名 extends 父类名{ }
-
原则
在类与类之间建立继承关系时,必须符合
is a
(是一个...)要符合现实生活中的认知
比如
Java
学生是一个学生- 猫是一个动物
- 冰箱是一个电器
如果是如下就不符合了
Java
学生是一个电器
四、使用继承改造代码
新增一个Student
类,把JavaStudent
类和UIStudent
类中的相同特征进行抽取,如下
Student.java
// Student.java
public class Student {
private String number; // 学号
private String name; // 姓名
private int age; // 年龄
private String classes; // 班级
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
// ...(其他属性get、set方法;Student空参构造方法、有参构造方法)
// 考试
public void exam(){
System.out.println("考试");
}
// 登录
public boolean login(String stuNo, String pwd){
System.out.println("登录");
return true;
}
}
JavaStudent.java
public class JavaStudent extends Student{
private String project; // 项目
//...(project属性get、set方法、JavaStudent空参构造方法、有参构造方法)
}
UIStudent.java
public class UIStudent extends Student{
private String opus; // 作品
//...(opts属性get、set方法、UIStudent空参构造方法、有参构造方法)
}
上述代码JavaStudent
类和UIStudent
类就继承了Student
类,抽取完相同特征后,JavaStudent
类和UIStudent
类只保留了一些特有的特征,子类就可以访问父类的非私有成员。虽然此时JavaStudent
类和UIStudent
类不能直接访问父类的私有属性,但可以通过get
、set
方法进行访问,建立一个测试类验证
public class Test {
public static void main(String[] args) {
JavaStudent javaStu = new JavaStudent("阿里云盘");
javaStu.setNumber("10010");
javaStu.setName("张三");
javaStu.setAge(27);
javaStu.setClasses("302");
System.out.println(javaStu.getName() + "---" + javaStu.getProject()); // 张三---阿里云盘
javaStu.exam(); // 使用父类的方法打印——考试
}
}
五、使用规范
工作中对于继承应该遵循如下规范
- 多个类相同特征(共性属性、共性方法)放在父类中定义
- 子类扩展的属性和方法应该定义在本子类中
六、父子类的对比
- 子类和父类相比,子类的功能更强大
- 子类和父类相比,父类的范围表示更广
七、继承后子类对象的内存原理
基于上述代码,当你在测试类Test.java
中new
一个子类JavaStudent.java
的时候,系统就会在堆内存中开辟一块新的空间,这个空间就属于javaStu
这个对象,此时,这个空间一分为二,一块叫做父类成员空间super
,一块叫做子类成员空间this
,当我们使用考试方法时javaStu.exam()
,会首先进入子类成员空间进行查找,结果是没有找到,接着会进入父类成员空间查找,结果找到了,就调用
总结如下:
子类对象在创建时,在堆内存中开辟的空间包含了两部分内容
- super空间:存储父类的相关成员
- this空间:存储了子类自身的相关成员
子类对象在访问成员时:
- 优先使用子类自己的成员,当子类没有该成员时,去super空间中使用父类的成员,如果父类也没有,会一直向上查找,如果直至Object类都没有的话,会报错。
八、特点
- 单继承,只支持单继承,不支持多继承
- 一个父类可以有多个子类
- 多层继承,子类
C
继承父类B
,父类B
可以继承父类A
,如果一个类没有直接继承关系,默认继承Object
,因此,所有类都是Object
类的子类
九、访问特点
-
变量访问
在子类方法中访问一个变量,满足就近原则
- 先子类局部范围找
- 然后子类成员范围找
- 然后父类成员范围找,如果父类范围内还没有找到则报错
- 父类中私有的成员子类不能直接访问
如果局部变量、本类成员变量、父类成员变量重名,应该按照如下进行区分
- 局部变量直接访问
- 本类成员变量,使用
this
访问 - 父类成员变量,使用
super
访问 - 使用
this
访问时,如果子类没有找到,也会去父类进行查找
-
方法访问
通过子类对象访问一个方法也满足就近原则
- 子类成员范围找
- 父类成员范围找
- 不能直接访问父类中私有成员
如果父类中出现同名参数的访问,先优先使用子类的,要访问父类相同方法可以使用
super
关键字