一、前言
记录时间 [2024-05-14]
系列文章简摘:
面向对象 02:区分面向过程与面向对象,类和对象的关系
面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析
面向对象 04:三大特性之——封装,封装的含义和作用,以及在 Java 中的使用方式,附完整的测试案例代码
面向对象 05:三大特性之——继承,继承在 Java 中的相关使用,区分关键字 super 和 this,方法重写的注意点
更多 Java 相关文章,请参考专栏哦。
本文讲述面向对象编程的三大特性之——多态。通过案例分析,介绍了多态的基本概念、相关使用,以及优缺点等。此外,文章还讲述了关键字 instanceof 的使用方式,以及对象之间的类型转换。
面向对象编程(Object-Oriented Programming, OOP)的三大特性是封装、继承和多态,这三大特性是 OOP
的基础,为设计灵活、可维护和可扩展的软件系统提供了核心机制。
这三个特性共同构成了面向对象编程的基础,使开发者能够设计出高内聚、低耦合的软件系统,促进了软件工程的高效管理和复杂问题的有效解决。
- 高内聚:一个模块内部各个组成部分(如类的方法、函数、变量等)之间应该紧密关联,共同完成一个具体且单一的功能,不允许外部干涉。
- 低耦合:各模块之间的依赖关系应该尽可能地减少和简化,一个模块应尽量少地依赖其他模块,模块之间的接口应清晰、简单,且只暴露必要的功能给外部使用。
二、什么是多态
1. 基本概念
多态(Polymorphism)是面向对象编程的一个核心特性,即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
多态允许使用父类类型的引用来指向子类的对象,从而使得代码更具通用性、可扩展性和可维护性。
Java 实现多态主要依赖于以下几个关键概念:
- 继承与多态:
- 多态的实现基于继承,即一个子类可以从父类继承方法,然后可以根据需要重写这些方法来改变其行为。
- 当一个父类引用指向子类对象时,可以调用子类重写的方法,尽管引用的静态类型是父类,这就是多态的表现。
- 方法重写(Override):
- 子类可以重写(Override)父类的方法,提供自己特定的实现。这是实现多态的重要手段。
- 重写的方法需要有相同的签名(方法名、返回类型以及参数列表)。
- 动态绑定(Dynamic Binding / Late Binding):
- 在 Java 中,方法的调用是在运行时绑定的,这意味着实际执行哪个版本的方法(父类的还是子类的)取决于实际对象的类型,而不是引用的类型。这一过程称为动态绑定或晚期绑定。
- 抽象类与接口:
- 抽象类和接口为多态提供了另一种形式的实现。它们定义了方法的合同,具体的实现由子类完成,这增加了系统的灵活性和可扩展性。
2. 多态的优缺点
多态的优势:
- 灵活性:可以使用统一的接口来操作各种类型的对象,减少代码耦合度。
- 可扩展性:增加软件的可扩展性,易于添加新的子类而不影响现有的体系结构。
- 简化性:提高代码的可读性和可维护性,特别是在处理大量对象时。
多态的限制:
- 多态通常只适用于方法,不适用于属性。即使子类中重写了父类的属性,父类引用也只能访问到父类定义的属性。
- 当使用父类引用调用一个方法时,只能访问到在父类中定义过的方法,不能访问子类特有的方法。
- 由于动态绑定,某些情况下可能会牺牲部分运行效率;过多使用向上转型可能使代码的意图不够明确。
3. 案例分析
在 Java 中,一个对象实际类型是确定的,但它可以指向的引用类型是不确定的,比如:父类的引用指向子类。
准备两个父子关系的类
举例说明,准备两个父子关系的类,其中,Animal
是父类,Dog
是子类。
在父类中写了一个方法 sound()
// Animal 父类
public class Animal {// 在父类中写了一个方法 sound(),然后将该方法在子类中重写public void sound() {System.out.println("Animal makes a sound");}}
在子类中重写了从父类中继承的 sound()
方法,同时,写了一个子类中特有的方法 play()
// Dog 子类
public class Dog extends Animal {// 在子类中重写了从父类中继承的 sound() 方法@Overridepublic void sound() {System.out.println("Dog barks");}// 写了一个子类中特有的方法 play()public void play() {System.out.println("Dog plays");}}
引用对象实例化
对于子类 Dog
,它能调用的方法是自己的,或者从父类那里继承的。
父类引用可以指向子类,我们可以将父类 Animal
的引用指向子类 Dog
,也可以将 Object
的引用指向子类 Dog
。
public class Application {public static void main(String[] args) {// 一个对象实际类型是确定的
// new Dog();
// new Animal();// 可以指向的引用类型是不确定的,比如:父类的引用指向子类// 子类 Dog 能调用的方法是自己的,或者从父类那里继承的Dog dog = new Dog();// 父类 Animal 可以指向子类Animal animal = new Dog();Object obj = new Dog();}}
进行测试
测试一
子类重写了父类的方法,父类对象执行子类的方法。
// 子类重写了父类的方法,父类对象执行子类的方法animal.sound(); // 调用子类方法 Dog barks
dog.sound(); // 调用子类方法 Dog barks
在这个例子中,Animal
是父类,Dog
是子类。尽管 animal
被声明为 Animal
类型,但它实际上指向的是 Dog
类的一个实例。因此,调用 sound()
方法时,执行的是 Dog
类中重写的方法,这就是多态性的体现。
测试二
父类可以指向子类,但不能调用子类独有的方法。
对象能调用哪些方法,主要看对象左边的类型,和右边关系不大。
// 父类可以指向子类,但不能调用子类独有的方法
// animal.play();
dog.play();
在这个例子中,Animal
是父类,Dog
是子类。尽管 animal
实际上指向的是 Dog
类的一个实例,但不能调用 Dog
类独有的方法 play()
,该方法只有 Dog
类型的实例能调用。
4. 注意事项
以下是一些关于多态的注意事项:
注意事项:1. 多态是方法的多态,属性没有多态。2. 有联系的类才能进行类型转换(比如父类和子类),否则会抛出类型转换异常(ClassCastException)。3. 多态存在条件:继承关系,方法需要重写,父类引用指向子类 Father f1 = new Son();不能被重写的方法:1. static 方法,属于类,不属于实例2. final 常量类型3. private 私有类型补充:1. 子类重写了父类的方法,父类对象执行子类的方法。2. 父类可以指向子类,但不能调用子类独有的方法。
三、关键字 instanceof
1. 基本概念
instanceof
是 Java 中的一个关键字,用于判断一个对象是否属于某个类或其子类(或者实现了某个接口)。
使用 instanceof
的一个典型场景是在需要确定对象的具体类型,以便进行特定类型的操作时。
但要,频繁使用 instanceof
可能意味着设计不够面向对象,因为良好的面向对象设计倾向于使用多态来处理不同类型的对象,而不是通过类型检查来分支逻辑。
其语法形式如下:
object instanceof ClassName
其中,object
是要检查的对象,ClassName
是类名或接口名。
如果 object
是 ClassName
类的实例,或者是其子类的实例,或者是实现了 ClassName
接口的类的实例,那么 instanceof
表达式的结果就是 true
;否则,结果是 false
。
2. 案例分析
准备父子类和实例对象
例如,有五个类:Object
、Animal
、Dog
、Cat
、String
。
其中,Object
是 Animal
的父类,Animal
是 Dog
和 Cat
的父类。String
是 Object
的子类。
父子关系:
Object > String
Object > Animal > Dog
Object > Animal > Cat
准备一些实例对象:
// 正常的实例化
Object object = new Object();
Animal animal = new Animal();
Dog dog = new Dog();// 向上转型,父类引用指向子类实例,实际是子类的对象
Object object2 = new Dog();
Animal animal2 = new Dog();
使用 instanceof 判断
判断 object
对象与上述五个类之间的关系。
// Object > String
// Object > Animal > Dog
// Object > Animal > CatSystem.out.println("Object object = new Object();");System.out.println(object instanceof Object); // true
System.out.println(object instanceof Animal); // false
System.out.println(object instanceof Dog); // false
System.out.println(object instanceof Cat); // false
System.out.println(object instanceof String); // false
思考:通过 Object object = new Object();
实例化 object
对象。
object
是Object
类的对象,object instanceof Object
为true
;object
既不是其他四个类的对象,也不是四个类的子类的对象,故比较为false
。
同理,判断 object2
对象与上述五个类之间的关系。
// Object > String
// Object > Animal > Dog
// Object > Animal > Cat// 向上转型,父类引用指向子类实例,实际是子类的对象
Object object2 = new Dog();System.out.println("Object object2 = new Dog();");System.out.println(object2 instanceof Object); // true
System.out.println(object2 instanceof Animal); // true
System.out.println(object2 instanceof Dog); // true
System.out.println(object2 instanceof Cat); // false
System.out.println(object2 instanceof String); // false
思考:通过 Object object2 = new Dog();
实例化 object
对象。
object2
是Dog
类的对象,object2 instanceof Dog
为true
;object2
是Object
类的子类的对象,object2 instanceof Object
为true
;object2
是Animal
类的子类的对象,object2 instanceof Animal
为true
;object2
既不是Cat
和String
类的对象,也不是它们的子类的对象,故比较为false
。
完整的 instanceof 比较
完整的 instanceof
比较如下:
public class Application {public static void main(String[] args) {// instanceofObject object = new Object();Animal animal = new Animal();Dog dog = new Dog();Object object2 = new Dog();Animal animal2 = new Dog();System.out.println("Object object = new Object();");System.out.println(object instanceof Object); // trueSystem.out.println(object instanceof Animal); // falseSystem.out.println(object instanceof Dog); // falseSystem.out.println(object instanceof Cat); // falseSystem.out.println(object instanceof String); // falseSystem.out.println("Animal animal = new Animal();");System.out.println(animal instanceof Object); // trueSystem.out.println(animal instanceof Animal); // trueSystem.out.println(animal instanceof Dog); // falseSystem.out.println(animal instanceof Cat); // false
// System.out.println(animal instanceof String); // 编译时报错System.out.println("Dog dog = new Dog();");System.out.println(dog instanceof Object); // trueSystem.out.println(dog instanceof Animal); // trueSystem.out.println(dog instanceof Dog); // true
// System.out.println(dog instanceof Cat); // 编译时报错
// System.out.println(dog instanceof String); // 编译时报错System.out.println("Object object2 = new Dog();");System.out.println(object2 instanceof Object); // trueSystem.out.println(object2 instanceof Animal); // trueSystem.out.println(object2 instanceof Dog); // trueSystem.out.println(object2 instanceof Cat); // falseSystem.out.println(object2 instanceof String); // falseSystem.out.println("Animal animal2 = new Dog();");System.out.println(animal2 instanceof Object); // trueSystem.out.println(animal2 instanceof Animal); // trueSystem.out.println(animal2 instanceof Dog); // trueSystem.out.println(animal2 instanceof Cat); // false
// System.out.println(animal2 instanceof String); // 编译时报错}}
四、类型转换
1. 基本概念
在 Java 中,有继承关系的对象之间的转换主要涉及向上转型(Upcasting)和向下转型(Downcasting)。
- 向上转型(Upcasting):这是 Java 中最常见的对象转换形式,也是自动进行的,无需显式转换。将子类对象赋值给父类引用时,就发生了向上转型。向上转型是安全的,因为子类对象可以视为是父类类型的特殊实例。
- 向下转型(Downcasting):这是将父类引用转换为子类类型的过程,必须显式进行。因为向下转型可能导致类型不匹配的问题(比如父类引用实际上并未指向子类对象),所以需要使用
(子类类型) 父类引用
的语法,并且最好在转换前使用instanceof
检查,以避免ClassCastException
。
尝试将一个对象转换为与之无继承关系的类型时,Java 会在编译时报错。如果使用强制类型转换,运行时则会抛出 ClassCastException
异常。
2. 案例分析
向上转型,例如,将子类对象赋值给父类引用。
// 子类对象赋值给父类引用
Father father = new Son();
向下转型,例如,将父类强制转换成子类。
// 将父类强制转换成子类
// 注意使用 instanceof 检查,保证转换安全性
((Son)father);
还是以上面的类为例,准备两个父子关系的类,其中,Animal
是父类,Dog
是子类。
- 在父类
Animal
中写了一个方法sound()
; - 在子类
Dog
中重写了从父类中继承的sound()
方法,同时,写了一个子类中特有的方法play()
public class Application {public static void main(String[] args) {// 对象类型之间的转换// 向上转型:子类对象赋值给父类引用// 自动完成Animal obj = new Dog();// 向下转型:将父类强制转换成子类// 这样就可以调用子类私有的方法了((Dog)obj).play();}}
五、总结
本文讲述面向对象编程的三大特性之——多态。通过案例分析,介绍了多态的基本概念、相关使用,以及优缺点等。此外,文章还讲述了关键字 instanceof 的使用方式,以及对象之间的类型转换。
一些参考资料
狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/