Java 继承与多态⚓︎
约 1776 个字 54 行代码 预计阅读时间 10 分钟
继承⚓︎
继承(inheritance) 是面向对象设计方法论的重要组成部分,是一种将一个类的行为或实现定义为另一个类的超集的能力。简单地说,就是调用另一个类的方法和属性的能力。
继承的语法如下:
继承类型⚓︎
Java 不支持多继承,但支持多重继承。
不能同时继承多个类,但是每个类的父类都可以有一个父类(可以变相实现继承多个类)
继承的性质⚓︎
继承的属性和方法
- 子类拥有父类非 private 的属性、方法/子类对象的一部分就是父类对象--> 子类构造函数执行前,必须先初始化父类
- 子类可以拥有自己的属性和方法
- 子类可以用自己的方式实现父类的方法(重写)
继承的实现
- 继承可以使用
extends和implements实现,而且所有的类都是继承于java.lang.Object - 当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。
不会被继承的东西
- 构造函数
- 子类的构造函数需要自己写
new构造子类时,如果没有显式传递参数,子类会调用默认构造函数,父类会调用不父类中不含参的构造方法new构造子类时,如果有显式传递参数,子类含对应参数的构造函数必须用super调用父类中对应的带参构造器- 子类构造函数执行前,必须先初始化父类
- 私有数据被隐藏,但仍然存在
向上转型(upcasting):把子类对象当成父类来看待。
- 逻辑:因为“狗”一定是“动物”,所以
Animal a = new Dog();是绝对安全的。 - 后果:编译时,变量 a 的结构和方法都是 Animal 的。
方法调用绑定(method call binding)
- 静态绑定
- 定义:在程序 编译阶段(还没运行),编译器根据你 变量的类型 就决定了调用谁。
- 适用对象:
- 字段(属性):Java 属性不支持多态。
- 私有方法 (
private):外部看不见,无法重写。 - 静态方法 (
static):属于类,不属于对象。 - 构造函数:创建对象时固定调用的。
- 动态绑定
- 定义:在程序 运行阶段,JVM 根据 实际在内存里的那个对象 是谁,来决定调用谁。
-
适用对象:普通的实例方法(即被
override的方法)。 -
总结
- 编译看左边:属性、静态方法、私有方法,左边变量是什么类型,就用谁的。
- 运行看右边:普通实例方法,右边 new 出来的是什么对象,就执行谁的。
多态⚓︎
多态是同一个行为具有多个不同表现形式或形态的能力。
-
在多态下,引用对象(reference variable) 和对象类型(object type)可以是不同的类型
-
运用多态,引用类型可以是实际对象类型的父类
方法的重写和重载⚓︎
重写/覆盖的规则
- 参数必须要一样,且返回类型必须要兼容
- 父类使用了哪种参数,覆盖此方法的子类也一定要使用相同的参数
-
父类声明的返回类型是什么,子类必须要声明一样的返回类型
-
不能降低方法的存取权限
- 存取权限必须相同,或更为开放
- 不能覆盖掉一个 public 方法并将它标记为 private
重载的意义,是两个方法的名称相同,但参数不同
抽象⚓︎
抽象类⚓︎
抽象类是对所有从它派生出来的类的一个 公共接口。包含抽象方法的类。用 abstract 来声明
-
禁止实例化:抽象类不能实例化对象,它必须被继承,才能被使用,或者说抽象类是一种特殊的,专门用来被继承的类。可以视作是模板
-
允许“残缺”:它可以包含 抽象方法(用
abstract修饰,没有方法体{},只有一个签名)
抽象方法⚓︎
也是用 abstract 来声明,是不完整的,只有声明,没有方法体。
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
- 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
接口⚓︎
接口是完全的抽象类,用于被实现方法。通过 interface 声明
接口与类 、抽象列的区别
-
成员变量:接口不能包含成员变量,除了 static 和 final 变量。
-
接口中所有的数据成员都是
public static final -
构造方法: 接口没有构造方法。
-
方法: 接口中的所有方法都是
public的 -
接口中所有的方法必须是抽象方法(JDK 1.8 以后, 接口中可以使用 default 关键字修饰的非抽象方法、JDK 1.9 以后,允许将方法定义为 private)
-
实例化: 接口不能用于实例化对象。
- 继承: 接口不是被类继承了,而是要被类实现。
- 接口支持多继承--一个类只能继承一个抽象类,而一个类却可以实现多个接口。(继承与实现)
- 一个接口能继承另一个 / 多个接口,但不能继承自类
接口特点
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
- 接口中的方法都是公有的。
接口的实现
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
接口的多继承
接口支持多重继承,可能会遇到两个接口都提供了具有相同签名的默认方法的情况。有以下三条法则
- 任何类都优于任何接口。所以如果超类链中有一个带有方法体或抽象声明的函数,我们可以完全忽略接口。
- 子类型优于附类型。如果我们有两个接口抢着提供默认方法,并且其中一个接口扩展另一个接口,此时子类获胜。
- 没有规则 3。如果前两条规则不能给我们答案,子类必须实现该方法或声明它为抽象。
接口中的静态方法
- 属于接口本身,不被实现类继承,只能通过接口名调用,必须带方法体
- 默认
public,不允许写abstract,default,synchronized
| 类型 | 能不能 new? | 能不能有抽象方法? | 存在意义 |
|---|---|---|---|
| 普通类 | 能 | 不能 | 它是具体的,可以直接拿来用。 |
| 抽象类 | 不能 | 能 | “半成品”。提取公共特征,强迫子类统一标准。 |
| 接口 | 不能 | 全是(默认) | “协议”。定义具备某种能力(如:会飞、会游泳)。 |