本文目录
第9章 多态
1. 多态
多态性是面向对象中的第三大主要特征,多态性是在继承性的基础之上扩展出来的概念,也就是说可以实现父子类之间的相互转换处理。
1.1 多态的理解
多态指的是同一个行为具有多个不同表现形式。是指一个类实例(对象)的相同方法在不同情形下具有不同表现形式。封装
和 继承
是多态的基础,也就说明,多态只是一种表现形式而已。
如何实现多态?多态的实现具有是三种充要条件:
- 继承
- 重写父类方法
- 父类引用指向子类对象
绑定:一个方法的调用与方法所在的类的关联
- 前期绑定:在程序执行前,方法已经跟所在类绑定
后期绑定
:在运行时,调用的方法才跟对象的类型真正绑定在一起
而 Java 采用的就是后期绑定,因此 Java 也是一门动态语言。
编译期:判断引用变量所属的类是否有调用的方法
运行期:判断引用变量所指向的类是否有调用的方法
总结:编译看左边,运行看右边
1.2 多态的实现
在 Java 中对于多态性有两种实现的模式:
- 方法的多态性:
- 方法重载 :同一个方法名称可以根据传入参数的类型或者个数的不同实现不同功能的执行;
- 方法重写 :同一个方法可能根据子类的不同有不同的实现;
- 对象的多态性:父子实例之间的转换处理,它有两种模式
- 对象向上转型(接收或返回参数的统一性):父类 父类实例 = 子类实例, 自动完成转换
- 对象向下转型 :子类 子类实例 = (子类)父类实例, 强制完成转换
从实际的转型来讲,大部分情况下考虑最多的一定是对象向上转型(90%),对于对象的向下转型往往都在使用子类特殊功能(子类可以对父类进行功能扩充)的时候要采用向下转型(3%),还有一些时候是不会考虑转型的(String 类,7%)。
1.3 instanceof 关键字
instanceof:是 Java 的一个二元操作符,它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean
的数据类型。
示例代码:
String str = "Hello, world!";
System.out.println(str instanceof String); // true
1.4 多态的应用
- 应用程序不必为每个子类编写功能调用,只需要对父类进行处理即可,大大提高了程序的可复用性。
- 子类的功能可以被父类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。
2. 抽象类
在 Java 中,一个没有方法体的方法应定义为抽象方法,而一个类中包含一个或多个抽象方法时,该类则为抽象类。
2.1 为什么要使用抽象
- 引入抽象方法和抽象类,是 Java 提供的一种语法工具,对于一些类和方法,引导使用者正确使用它们,减少被误用。
- 使用抽象方法,而非空方法体,子类就知道他必须要实现该方法,而不可能忽略。
- 使用抽象类,类的使用者创建对象的时候,就知道他必须要使用某个具体子类,而不可能误用不完整的父类。
2.2 抽象方法和普通方法
使用 abstract
修饰的方法即为抽象方法(没有具体方法体),如下所示:
public abstract class AbstractClass { // 抽象类
public abstract void show(); // 抽象方法
}
不使用 abstract
修饰的方法即为普通方法,如下所示:
public class ClassName {
public abstract void show(){ // 普通方法
}
}
注意:抽象方法和空方法体不是同一个概念,例如:public abstract void show();
是一个抽象方法,因为它根本没有方法体,即方法定以后没有一对花括号( {}
);但是 public void test(){}
方法是一个普通方法,它已经定义了方法体,只是方法体为空,即它的方法体什么也不做。
2.3 抽象类的特点
- 抽象类和抽象方法必须用 abstract 关键字修饰
- public abstract class ClassName {}
- public abstract void eat();
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者是接口
- 抽象类不能实例化那么,抽象类如何实例化呢?
- 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
- 抽象类的子类
- 要么是抽象类
- 要么重写抽象类中的所有抽象方法
2.4 模板方法模式
定义:
- 定义一个操作中算法的骨架,而将一些步骤延迟到子类中
作用:
- 模板方法使得子类可以不改变一个算法的结构而可重定义该算法的某些特定步骤
3. 接口
3.1 接口概念
定义:
- 接口是抽象方法和常量值的定义的集合
- 本质上,接口是一种特殊的抽象类,只包含常量和方法定义,没有变量和方法实现
- 体现了程序的多态和高内聚低耦合
作用:
- 提供功能的扩展
- 解耦
特点:
- 接口不能被实例化
- 接口中的方法都说抽象方法
- 接口可以被其它类实现,使用
implements
关键字,一个类能实现多个接口,并且该类必须实现接口中的所有方法 - 接口中的变量本质上是
static
和final
的,也就是常量 - 接口不能继承其他类,但可以继承其它一个或多个接口(
Java
中的继承是单继承,而接口恰好弥补了多继承) - 接口中只能使用两种修饰符,
public
(对整个项目工程可见)和defaalt
缺省值(对其所在包中可见)
3.2 抽象类与接口
二者之间的异同:
相同点:
-
二者都不能被实例化:
- 抽象类中可以有构造方法,但不是用来实例化的,而是用于初始化的。
- 接口中不能存在构造方法,因为不能被实例化。
-
抽象类里的抽象方法必须全部被子类所实现,子类如果不能全部实现父类抽象方法,那么该子类只能是抽象类。一个类实现接口的时候,如果不能全部实现接口方法,那么该类也只能为抽象类。
-
抽象类和接口都不能被定义为
private
或final
,否则不能被继承或实现。
不同点:
-
抽象类要被子类继承,接口要被类实现。
-
抽象类可以作方法声明,也可以作方法实现,而接口只能作方法声明。
-
抽象类中定义的变量是普通变量,接口中定义的变量只能是
public
且static final
的常量。 -
抽象类是重构的结果,接口是设计的结果。
-
抽象类和接口都是用来抽象具体对象的,但是接口的抽象级别最高,接口相当于抽象类的特例。
-
抽象类可以有具体的方法和属性,接口只能有抽象方法和不可变常量。
-
抽象类是事物的提取,接口是功能的扩展。
-
抽象类只支持单继承(但可以实现一个或多个接口),而接口支持多继承(只能继承接口)
3.3 接口实现多继承
接口可以继承接口,并且可继承多个接口,但接口不能实现(implements
)任何接口
在 Java 中,类的多继承是不合法,但接口允许多继承。
在接口的多继承中 extends
关键字只需要使用一次,在其后跟着继承接口。 如下所示:
public interface Hockey extends Sports, Event, ...
3.4 接口的使用
接口的使用与类的使用有些不同。在需要使用类的地方,会直接使用 new
关键字来构建一个类的实例,但接口不可以这样使用,因为接口不能直接使用 new
关键字来构建实例。
接口必须通过类来实现(implements
)它的抽象方法,然后再实例化类。类实现接口的关键字为 implements
。
如果一个类不能实现该接口的所有抽象方法,那么这个类必须被定义为抽象方法。
不允许创建接口的实例,但允许定义接口类型的引用变量,该变量指向了实现接口的类的实例。
一个类只能继承一个父类,但却可以实现多个接口。
实现接口的格式如下:
修饰符 class 类名 extends 父类 implements 多个接口 {
// 实现方法
}
3.5 常用接口
Comparable :
- 实现
Comparable
接口的类,实现该接口中唯一的compareTo(Object o)
方法后,可以使得类和类之间可以进行比较
Cloneable :
- 一个类实现
Cloneable
接口,以指示Object.clone()
方法,该方法对于该类的实例进行现场复制是合法的。- 在不实现
Cloneable
接口的实例上调用对象的克隆方法导致抛出异常CloneNotSupportedException
。- 按照惯例,实现此接口的类应使用公共方法覆盖
Object.clone()
,因为该方法是protected
(受保护的)。
浅克隆与深克隆:
- 浅克隆:克隆对象的时候,并没有对克隆对象中的
引用类型变量
进行克隆 - 深克隆:克隆对象的时候,对克隆对象中的
引用类型变量
也进行了克隆
3.6 适配器模式
适配器模式:
- 定义:将一个类的接口转换客户端希望的另外一个接口
- 作用:使得原本由于接口不兼容而不能在一起的那些类可以一起工作
示例代码:
/**
* 功能接口
*/
interface MyInterface {
void m1();
void m2();
void m3();
void m4();
}
/**
* 适配器
*/
class Adapter implements MyInterface{
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
}
/**
* 只需要 MyInterface 中的 m3()
*/
class MyClass extends Adapter{
@Override
public void m3() {
super.m3();
}
}
4. Object 类中常见的方法
- equals 和 hashCode
- equals:比较此对象与传入对象是否相等
- hashCode:返回对象的哈希码值
- toString:返回对象的字符串表现形式
认真、沉着做事,每天进步一小点!!!