学习Java第十四天--面向对象三大特性之多态

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 总结

  • 多态的两种应用场景:
    使用父类作为方法的形参,实现多态;
    调用方法时,可传递的实参类型包括:本类型对象+其所有子类对象;
    使用父类作为方法的返回值,实现多态:
    调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象;

  • 多态的作用:
    屏蔽子类间的差异;
    灵活、耦合度低;

发布了34 篇原创文章 · 获赞 7 · 访问量 1302

猜你喜欢

转载自blog.csdn.net/weixin_44257082/article/details/104414195