我的身旁是一扇亮了又暗的窗

0%

继承

概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。如图所示:

image-20200406161705307

其中,多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类

继承描述的是事物之间的所属关系,这种关系是:is-a的关系。例如,图中兔子属于食草动物,食草动物属于动物。可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。

定义

  • 继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

好处

  1. 提高代码的复用性(共性抽取)
  2. 类与类之间产生了关系,是多态的前提(没有继承,就没有多态)

01-继承的基本概念

继承的格式

  • 通过extends关键字,可以声明一个子类继承另外一个父类

  • 格式

1
2
3
4
5
6
class 父类{
// 代码
}
class 子类 extends 父类{
// 代码
}
  • 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {

public static void main(String[] args) {
Student student = new Student();
student.lectures();
}

}
class Teacher{
public void lectures(){
System.out.println("在给学生讲课");
}
}
class Student extends Teacher{

}

继承后的特点–成员变量

成员变量不重名

如果子类父类中出现不重名的成员变量,这时的访问是没有影响的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {

public static void main(String[] args) {
Fu fu = new Fu();
System.out.println(fu.numfu);
Zi zi = new Zi();
System.out.println(zi.mumzi+":"+zi.numfu);
}

}
class Fu{
int numfu = 10;
}
class Zi extends Fu{
int mumzi = 20;
}

成员变量重名

子类父类中出现重名的成员变量,访问有两种方式

  1. 直接通过子类对象访问成员变量
    • 规则:等号左边是谁,就优先用谁,如果没有则向上找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {

public static void main(String[] args) {
Fu fu = new Fu();
System.out.println(fu.num); // 100

Zi zi = new Zi();
System.out.println(zi.num); // 10

}

}
class Fu {
int num = 100;
}
class Zi extends Fu {
int num = 10;
}
  1. 简介通过成员方法访问成员变量
    • 该方法属于谁,就优先用谁,没有则想上找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test {

public static void main(String[] args) {
Fu fu = new Fu();
fu.methodFu(); // 100

Zi zi = new Zi();
zi.methodZi(); // 10
zi.methodFu(); // 100
}

}
class Fu {
int num = 100;
public void methodFu(){
System.out.println(num);
}
}
class Zi extends Fu {
int num = 10;

public void methodZi(){
System.out.println(num);
}
}

区分子类方法中重名的三种变量

  • 成员变量
  • 本类的成员变量
  • 父类的成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {

public static void main(String[] args) {
Zi zi =new Zi();
zi.method();
}

}
class Fu {
int num = 10;

}
class Zi extends Fu {
int num = 20;

public void method(){
int num = 30;
System.out.println(num); // 局部变量
System.out.println(this.num); // 本类的成员变量
System.out.println(super.num); // 父类的成员变量
}
}

继承后的特点–成员方法

在父子类的继承关系中,创建子类对象,访问成员方法的规则:

  • 创建的对象是谁,就优先用谁,如果没有则想上找
  • 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的

成员方法不重名

如果子类父类中出现不重名的成员方法,这时的调用是没有影响的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {

public static void main(String[] args) {
Zi zi =new Zi();
zi.method1();
zi.method2();
}

}
class Fu {
public void method1(){
System.out.println("method2");
}
}
class Zi extends Fu {
public void method2(){
System.out.println("method2");
}
}

成员方法重名–重写(Override)

如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写(Override)

  • 方法重写:子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
  • @Override 是可选的注解,如果不写,满足要求也是正确的方法覆盖重写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {

public static void main(String[] args) {
Zi zi =new Zi();
zi.method();
}

}
class Fu {
public void method(){
System.out.println("method2");
}
}
class Zi extends Fu {
@Override
public void method(){
System.out.println("method2");
}
}

注意事项

  • 子类方法覆盖父类方法,必须要保证权限大于等于父类权限
  • 子类方法覆盖父类方法,返回值类型必须小于等于父类方法的返回值范围
  • 子类方法覆盖父类方法,函数名和参数列表都要一模一样

继承后的特点–构造方法

构造方法的定义格式和作用

  • 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
  • 构造方法的作用是初始化成员变量的。
    • 所以子类的初始化过程中,必须先执行父类的初始化动作。
    • 子类的构造方法中默认有一个super(),表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
    • 就算没有写super(),也会自动调用父类的构造方法
    • 子类构造可以通过super()关键字来电泳父类重载构造
    • super的父类构造调用,必须是子类构造方法的第一个语句
    • 不能一个子类构造调用多次super构造
  • 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {

public static void main(String[] args) {
Zi zi = new Zi();
// Fu()
// Zi()
}

}

class Fu {
Fu() {
System.out.println("Fu()");
}
}

class Zi extends Fu {
Zi() {
// super(); 调用父类构造器
System.out.println("Zi()");
}
}

super关键字的三种用法和this关键字的三种用法

  1. super

    1. 在子类的成员方法中,调用父类的成员变量
    2. 在子类的成员方法在,嗲用父类的成员方法
    3. 在子类的构造方法中,方法父类的构造方法
  2. this

    1. 在本类的成员方法中,访问本类的成员变量
    2. 在本类的成员方法中,访问本类的另一个成员方法
    3. 在本类的构造方法中,访问本类的另一个构造方法
  3. 注意事项

    1. this()和super()调用都必须是构造方法的第一个语句,唯一一个
    2. super和this两种构造调用,不能同时使用

super和this图解

03-super与this的内存图

继承的特点

  • Java只支持单继承,不支持多继承
  • Java语言可以多继承
  • 一个子类的直接父类是唯一的,但是一个父类可以拥有多个子类
  • 顶层父类是Object类,所有的类默认继承Object,作为父类

04-Java继承的三个特点