面向对象三大特性三(多态)
多态是面向对象的三大特征之一。
1.概念
多态一词的通常含义是指能够呈现出多种不同的形式或形态。而在程序设计术语中,它意味着一个特定类型的变量,可以引用不同类型的对象,并且能自动地调用引用的对象的方法。
也就是根据用到的不同对象类型,响应不同的操作。方法重写是实现多态的基础。通过下面的例子可以简单认识什么是多态。
public class Pet {
public void toHospital() {
System.out.println("宠物去医院");
}
}
class Dog extends Pet {
@Override
public void toHospital() {
System.out.println("狗去医院");
}
}
class Bird extends Pet {
@Override
public void toHospital() {
System.out.println("鸟去医院");
}
}
class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.toHospital();
Bird bird = new Bird();
bird.toHospital();
Pet pet;
pet = new Dog();
pet.toHospital();
pet = new Bird();
pet.toHospital();
}
}
多态意味着在一次方法调用中根据包含的对象的实际类型(即实际子类的对象)来决定应该调用哪个子类的方法,而不是由用来存储对象引用的变量的类型决定的。当调用一个方法时,为了实现多态操作,这个方法即是在父类中声明过的,也必须是在子类中重写过的方法。
2.使用
- 方法重写是多态的基础
- 多态中,变量引用的是哪个对象,就执行的是哪个对象中相对应的方法
3.类型转换
3.1向上转型
子类向父类转换称为向上转型。
向上转型的语法格式如下:
父类类型 引用变量名 = new 子类类型();
例如: Pet pet = new Dog();
之前介绍了基本数据类型之间的类型转换,
-
把int类型常量或变量赋值给double类型的变量,可以自动进行类型转换。
-
把double类型的常量或变量赋值给int类型的变量,必须进行强制转换。实际上在引用数据类型的子类和父类之间也存在着类型转换问题
Pet pet = new Dog(); // 子类转换成父类,也称为父类引用指向子类对象
pet.toHospital(); // pet 对象调用的是Dog类的toHospital() 方法,体
现了多态。
多态就是说一个父类可能有多个子类,每个子类都重写了父类的方法(每个子类都有不同的方法实现),当父类引用调用方法时,父类引用指向哪个子类,就调用哪个子类的方法,形成了父类引用调用相同的方法名称时,有不同的输出形态。
- 子类继承父类,并且子类重写父类的方法。
- 父类引用指向子类对象(父类引用可以指向任意一个子类的对象)。
- 父类引用调用方法时,实际上调用的是子类的方法(父类指向哪个子类就调用哪个子类的方法),不同的子类有不同的方法实现,体现出同一个方法在不同子类中的不同形态的表现。
此外,调用的时候应当注意:
- 父类只能调用子类从父类继承的方法或重写的方法。
- 父类不能调用子类新增的方法。
3.2向下转型
前面已经提到,当向上转型发生后,将无法调用子类新增的方法。但是如果需要调用子类新增的方法,可以通过把父类转换为子类实现。
将一个指向子类对象的父类引用赋值给一个子类的引用,即将父类类型转换为子类类型,称为向下转型,此时必须进行强制类型转换。
向下转型的语法规则如下。
子类类型 引用变量名 = (子类类型) 父类类型的引用变量;
例如: Dog dog = (Dog)pet;
3.3instanceof 运算符
在向下转型过程中,如果不是转换为真实的子类类型,会出现类型转换异常。所以在Java中提供了instanceof运算符来进行类型转换的判断。
- 使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误。
- 在使用instanceof时,先判断获取的对象是否是某一类型,再做强制类型转换,然后再对对象进行操作。这是传统的写法,在Java 16的增强之后,对于instanceof的判断以及类型转换可以合二为一了
- 此外,在Java中,可以使用getClass()方法来进行类型转换的判断。getClass()方法是Object类的一个方法,所有Java类都继承自Object类,因此它可以在任何对象上调用。
getClass()返回的是运行时类的Class对象,所以比较时要使用==运算符,而不是使用equals()方法。另外,使用getClass()方法进行类型转换的判断通常用于处理特定类型的对象,而不是用于处理继承层次结构的类型判断。在处理继承层次结构时,通常会使用instanceof运算符来进行更灵活和安全的类型检查。
4.多态的应用
- 从上面的例子不难发现,多态的优势非常突出。
- 可替换性:多态对已存在的代码具有可替换性。
- 可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态。
- 接口性:多态是父类向子类提供了一个共同接口,由子类来具体实现。
- 灵活性:多态在应用中体现了灵活多样的操作,提高了使用效率。
- 简化性:多态简化了应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
在多态的程序设计中,一般有以下两种主要的应用形式。
4.1使用父类作为方法的参数
public void goHospital(Pet pet) {
pet.toHospital();
}
4.2使用父类作为方法的返回值
public Pet donateAnimal(String type){
Pet pet=null;
if("dog".equals(type)){
pet=new Dog();
}else if("bird".equals(type)){
pet=new Bird();
}else{
pet=new Pet();
}
return pet;
}