一.多态
要了解向上转型与向下转型,首先需要了解多态的概念
1.多态的概念
多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。——>百度百科
通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。
以动物发出叫声为例,当狗叫时的声音是“汪汪汪”,猫叫的时候是“喵喵喵”。同一件事情(发出叫声),发生在不同对象身上(狗和猫),就会产生不同的结果(汪和喵)。
2.多态实现条件
1. 必须在继承体系下
2. 子类必须要对父类中方法进行重写
3. 通过父类的引用调用重写的方法(向上转型)
在如下代码中,Dog类和Cat类继承了Animal(满足1),并对方法bark()进行了重写(满足2),并通过父类的引用animal1和animal2调用了重写的方法bark()(满足3)。
public class Animal {
String name;
int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void bark(){
System.out.println(name + ": 叫叫叫");
}
}
class Cat extends Animal{
public Cat(String name, int age){
super(name, age);
}
@Override
public void bark(){//对父类方法进行重写
System.out.println(name+": 喵喵喵");
}
}class Dog extends Animal {
public Dog(String name, int age){
super(name, age);
}
@Override
public void bark(){//对父类方法进行重写
System.out.println(name+": 汪汪汪");
}
}
class TestAnimal {
public static void main(String[] args) {
Animal animal1 = new Cat("新鲜哥",2);
Animal animal2 = new Dog("旺财", 3);
animal1.bark();//通过父类引用,调用重写方法
animal2.bark();//通过父类引用,调用重写方法
}
}
运行结果,(同一件事情,发生在不同对象上,产生了不同的结果)
二.动态绑定
在上述代码中使用父类的引用来调用一个被子类重写的方法(animal1.bark())的同时,发生了动态绑定。
1.动态绑定的定义
动态绑定(也称为晚期绑定或运行时绑定)是一种在程序运行时(而非编译时)确定要调用的具体方法的过程。这种机制的实现主要依赖于面向对象编程中的多态性。
2.动态绑定的实现
在Java中,动态绑定通常通过虚函数表(VTable)实现,每个类都有一个虚函数表,表中存储了该类虚函数的地址。当对象的方法被调用时,JVM会根据对象的实际类型找到对应的虚函数表,并调用相应的方法(即在运行时,确定要调用的具体方法)。
三.向上转型
1.向上转型的定义
指的是将子类的对象赋值给父类类型的引用
2.向上转型的写法
如下代码中,Cat继承Animal类成为其子类,在main函数中,子类对象Dog,赋值给了父类类型引用animal,实现了向上转型
public class Animal {//父类animal
String name;
int age;
public Animal(String name, int age){
this.name = name;
this.age = age;
}
public void bark(){
System.out.println(name + ": 叫叫叫");
}
}class Dog extends Animal {//子类dog
public Dog(String name, int age){
super(name, age);
}
@Override
public void bark(){//对父类方法进行重写
System.out.println(name+": 汪汪汪");
}
}
class TestAnimal {
public static void main(String[] args) {
Animal animal = new Dog("旺财", 3);//将子类的对象赋值给父类类型的引用
}
}
3.向上转型特点
不能调用到子类特有的方法
如下图中父类引用调用子类特有方法eat()时编译器会报错
原因:编译器在编译时只检查引用的类型(即父类),而不是实际对象的类型(即子类)。因此,如果尝试通过父类引用调用子类特有的方法,编译器会报错,因为它无法在父类中找到这个方法
且向上转型是实现多态性的一种方式。多态性允许我们使用父类引用来引用不同类型的子类对象,并通过这个引用调用在这些子类中以不同方式实现的父类方法。但是,多态性是基于父类中声明的方法实现的,而不是子类特有的方法。
4.为什么向上转型可以
比如,猫和狗都是动物,因此将子类对象转化为父类引用是合理的,因为你可以说猫和狗都是动物,大的范围可以囊括小的范围,是合理的,安全的。
5.小结向上转型,动态绑定,多态之间的关系
多态性要求在运行时根据对象的实际类型来确定方法的行为,而动态绑定机制可以根据对象的实际类型来确定调用哪个具体的方法,因此动态绑定是实现多态性的机制,
由于使用向上转型,使得通过父类引用调用方法时,JVM无法直接确定调用哪个类的方法,此时,动态绑定机制会根据对象的实际类型来查找并调用相应的方法。因此向上转型触发了动态绑定机制
因此通过向上转型,触发了动态绑定机制,从而实现了多态性。
四.向下转型
1.向下转型目的
上面说到将一个子类对象经过向上转型之后当成父类方法使用,但无法调用子类特有的方法,但有
时候可能需要调用子类特有的 方法,此时:将父类引用再还原为子类对象即可,即向下转型。
2.向下转型的风险
向上转型是大范围包括小的范围,是安全的,但向下转型是大范围缩小为小范围,比如说,你说狗是动物和猫是动物都是正确的,但如果你说动物是狗,动物是猫,就是错误的了。
如下图中,animal本来指向的对象就是Dog对象,转换成功,但animal指向的不是Cat对象,运行报错。
3.instanceof
为提升向下转型的安全性,java引入了instanceof
inscanof是一个二元运算符,用于在运行时检查对象是否是特定类的一个实例,或者是该类的任何一个子类的实例。instanceof通过返回一个布尔值(true或false)来表明对象是否是指定类或其子类的实例。
如下如果引用inscanof可以提升向下转型过程的安全性
public static void main(String[] args) {
Animal animal = new Dog("旺财", 3);//将子类的对象赋值给父类类型的引用
if (animal instanceof Dog){
Dog dog = (Dog)animal;//animal本来指向的就是Dog对象,
}
if (animal instanceof Cat){
Cat cat = (Cat)animal;
}
}
}
五.总结
1.向上转型条件
1.1必须在继承体系下
2.子类必须要对父类中方法进行重写
3. 通过父类的引用调用重写的方法(向上转型)
3.1向上转型不能调用到子类特有的方法
3.2要调用子类特有方法需进行向下转型
3.3instanceof可提升向下转型过程的安全性