多态的概念,应用
8.4 多态
8.4.1 多态的概念
-
生活中,不同人物角色看待同一个对象的视角不同,关注点也不同;
-
生活中的多态:
生活中的多态是指“客观事物在人脑中的主观反应”;
主观意识上的类别与客观存在的对象具有“is a”关系时,即形成多态; -
程序中的多态:
概念:父类引用指向子类对象,从而产生多种形态;
父类引用(引用类型)Animal a = new Dog(); 子类对象(对象类型); -
二者具有直接或间接的继承关系时,父类引用可指向子类对象,即形成多态;
-
父类引用仅可调用父类所声明的属性和方法,不可调用子类独有的属性和方法;
8.4.2 多态中的方法覆盖
- 思考:如果子类中覆盖了父类中的方法,以父类型引用调用此方法时,优先执行父类还是子类中的方法?
- 实际运行过程中,依旧遵循覆盖原则,如果子类覆盖了父类中的方法,则执行子类中覆盖后的方法,否则执行父类中的方法。
public class TestApplyPolymorphic {
public static void main(String[] args) {
Car car = new Car();//自身类型引用指向自身类型对象
car.brand = "BMW";//独有属性
car.price = 300000D;
car.speed = 60;
car.type = "小汽车";
car.run();
Vehicle veh = new Car();//父类引用指向子类对象
veh.type = "小汽车";
veh.price = 200000D;
veh.speed = 50;
veh.run();//调用的是子类覆盖了父类的方法
}
}
class Vehicle{
String type;
int speed;
double price;
public void run() {
System.out.println("一辆价值"+price+"的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Car extends Vehicle{
String brand;
public void run() {
System.out.println("一辆价值"+price+"的"+brand+"品牌的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
8.4.3 多态的应用
class Master{
public void feed(Dog dog){
dog.eat();
}
public void feed(Cat cat){
cat.eat();
}
public void feed(Fish fish){
fish.eat();
}
//...
}
- 方法重载可以解决接收不同对象参数的问题,但其缺点也比较明显;
- 首先,随着子类的增加,Master类需要继续提供大量的方法重载,多次修改并重新编译源文件。其次,每个feed方法与具体某一种类型形成了密不可分的关系,耦合太高。
- 场景一:
使用父类作为方法形参实现多态,使方法参数的类型更为宽泛。
public class TestApplyPolymorphic {
public static void main(String[] args) {
Employee emp = new Employee();
emp.name = "tom";
Bus bus = new Bus();
bus.type = "公交车";
bus.speed = 50;
bus.price = 1500000D;
bus.seatNum = 20;
emp.goHome(bus);
Bicycle bic = new Bicycle();
bic.type = "自行车";
bic.price = 300D;
bic.speed = 20;
bic.color = "白";
emp.goHome(bic);
}
//员工
class Employee{
String name;
//父类类型作为方法形参,实现多态
public void goHome(Vehicle veh){
System.out.print("下班了"+name+"乘坐");
veh.run();
}
}
class Vehicle{
String type;
int speed;
double price;
public void run() {
System.out.println("一辆价值"+price+"的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Car extends Vehicle{
String brand;
public void run() {
System.out.println("一辆价值"+price+"的"+brand+"品牌的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Bus extends Vehicle{
int seatNum;
public void run() {
System.out.println("一辆价值"+price+"有"+seatNum+"个座位的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Bicycle extends Vehicle{
String color;
public void run() {
System.out.println("一辆价值"+price+"的"+color+"色的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
- 场景二:
使用父类作为方法返回值实现多态,使方法可以返回不同子类对象。
public class TestPolymorphic {
public static void main(String[] args) {
Employee emp = new Employee();
emp.name = "tom";
Vehicle myVeh = emp.buyVeh(1200000D);
if(myVeh != null) {
if(myVeh instanceof Bus) {
Bus bus = (Bus)myVeh;
emp.goHome(bus);
}else if(myVeh instanceof Car){
Car car = (Car)myVeh;
emp.goHome(car);
}else if(myVeh instanceof Bicycle) {
Bicycle bic = (Bicycle)myVeh;
emp.goHome(bic);
}
}
}
}
//员工
class Employee{
String name;
//父类类型作为方法形参,实现多态
public void goHome(Vehicle veh){
System.out.print("下班了"+name+"乘坐");
veh.run();
}
public Vehicle buyVeh(double money) {//返回值为引用父类类型,实现多态
if(money > 1000000.0) {
Bus bus = new Bus();
bus.type = "公交车";
bus.speed = 50;
bus.price = 1000000D;
bus.seatNum = 20;
return bus;
}else if(money > 500000.0) {
Car car = new Car();
car.type = "小汽车";
car.brand = "BWM";
car.price = 500000.0;
car.speed = 60;
return car;
}else if(money > 2000.0) {
Bicycle bic = new Bicycle();
bic.type = "自行车";
bic.price = 2000D;
bic.speed = 20;
bic.color = "白";
return bic;
}else {
return null;
}
}
}
class Vehicle{
String type;
int speed;
double price;
public void run() {
System.out.println("一辆价值"+price+"的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Car extends Vehicle{
String brand;
public void run() {
System.out.println("一辆价值"+price+"的"+brand+"品牌的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Bus extends Vehicle{
int seatNum;
public void run() {
System.out.println("一辆价值"+price+"有"+seatNum+"个座位的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
class Bicycle extends Vehicle{
String color;
public void run() {
System.out.println("一辆价值"+price+"的"+color+"色的"+type+"以"+speed+"/h的速度行驶在路上");
}
}
8.4.4 向上转型(装箱)
public class TestConvert {
public static void main(String[] args) {
Animal a = new Dog();
}
}
class Animal{
public void eat() {
System.out.println("动物在吃...");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗在吃骨头...");
}
}
- 父类引用中保存真实子类对象,称为向上转型(即多态核心概念);
- 注意:仅可调用Animal中所声明的属性和方法;
8.4.5 向下转型(拆箱)
public class TestConvert {
public static void main(String[] args) {
Animal a = new Dog();
Dog dog = (Dog)a;
}
}
class Animal{
public void eat() {
System.out.println("动物在吃...");
}
}
class Dog extends Animal{
public void eat() {
System.out.println("狗在吃骨头...");
}
}
- 将父类引用中的真实子类对象,强转回子类本身类型,称为向下转型;
- 注意:只有转换回子类真实类型,才可调用子类独有的属性和方法;
8.4.6 类型转换异常
8.4.7 instanceof关键字
- 向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性;
- 语法:引用 instanceof 类型 //返回boolean类型结果;
public class TestConvert2 {
public static void main(String[] args) {
Animal a = new Dog();
if(a instanceof Dog) {
Dog dog = (Dog)a;
dog.eat();
}else if(a instanceof Cat) {
Cat cat = (Cat)a;
cat.eat();
}
}
}
- 当“a”引用中存储的对象类型确实为Dog时,再进行类型转换,进而调用Dog中的独有方法;
8.4.8 总结
-
多态的两种应用场景:
使用父类作为方法的形参,实现多态;
调用方法时,可传递的实参类型包括:本类型对象+其所有子类对象;
使用父类作为方法的返回值,实现多态:
调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象; -
多态的作用:
屏蔽子类间的差异;
灵活、耦合度低;