2022-07-22 第五小组 顾祥全 学习笔记 day15-JavaSE-面向对象-多态

面向对象-多态

什么是多态?

多态,即多种形态、多种状态。编译期一种形态,运行期一种形态。
多态核心代码:父类型引用指向子类型对象

public class Test {
	public static void main(String[] args){
		//父类型引用指向子类型对象
		Animal cat = new Cat();
		Animal dog = new Dog();
		//调用eat()
		cat.eat();
		dog.eat();
	}
}

class Animal {
	public void eat(){
		System.out.println("动物都能吃东西");
	}
}

class Cat extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("猫吃猫粮");
	}
}

class Dog extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("狗吃狗粮");
	}
}

上述代码运行结果如下
在这里插入图片描述

对于上面的代码可以这样解释(Java程序的运行分为编译阶段和运行阶段)

  • 在编译阶段,编译器只会检查语法,编译器检测到cat引用是Animal类型,编译器会到Animal.class字节码文件中去寻找eat(),找到后绑定Animal的eat()方法,完成编译阶段的绑定(静态绑定)
  • 在运行阶段,通过引用会通过引用找到对象并检测到该对象是Cat类型,找到后绑定Cat对象的eat()方法,完成运行阶段的绑定(动态绑定)

向上转型和向下转型

转型条件:只有存在继承关系才可以转型

向上转型

子类型 —> 父类型
向上转型可以自动转换

向下转型

父类型 —> 子类型
向下转型需要加强制类型转换符

何时需要使用向下转型

在多态中,父类型引用子类型对象时,如果需要访问子类特有的属性或方法时,需要向下转型,否则编译无法通过。

public class Test {
	public static void main(String[] args){
		//父类型引用指向子类型对象(自动类型转换)
		Animal cat = new Cat();
		Animal dog = new Dog();

		//子类特有方法catchMouse()
		cat.catchMouse();
	}
}

class Animal {
	public void eat(){
		System.out.println("动物都能吃东西");
	}
}

class Cat extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("猫吃猫粮");
	}
	public void catchMouse() {
		System.out.print("猫抓老鼠");
	}
}

class Dog extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("狗吃狗粮");
	}
}

在这里插入图片描述

在编译期,编译器会检测到cat引用时Animal类型,编译器会到Animal.class中寻找catchMouse(),而Animal.class中并没有catchMouse(),所以编译器报错。

向上转型可能会出现的异常

在多态中,父类型引用指向子类型对象,在运行阶段会检测引用实际指向的对象,如果向上转型转换类型出错,并不会在编译期出现问题,但在运行期会抛出类型转换异常(java.lang.ClassCastException)

public class Test {
	public static void main(String[] args){
		//父类型引用指向子类型对象
		Animal dog = new Dog();
		Cat d = (Cat)dog;

	}


class Animal {
	public void eat(){
		System.out.println("动物都能吃东西");
	}
}

class Cat extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("猫吃猫粮");
	}
	public void catchMouse() {
		System.out.print("猫抓老鼠");
	}
}

class Dog extends Animal {
	//重写eat()
	public void eat() {
		System.out.println("狗吃狗粮");
	}
}

在这里插入图片描述

在编译期,Animal类型的dog引用经过转型后变成Cat类型并将对象的地址给Cat类型的d引用,编译器检测到d是Cat类型所以编译能通过,但是在程序运行期间,检测到d引用指向的对象实际是Dog类型,所以会抛出类型转换异常(java.lang.ClassCastException)

如何避免ClassCastException

  使用instanceof运算符判断引用指向对象的类型后再向下转型

instanceof运算符特点

  1. instanceof用于检测引用指向的对象数据类型
  2. instanceof运算结果是true/false
  3. instanceof语法格式:引用 instanceof 数据类型

具体代码如下

public class Test {
	public static void main(String[] args){
		Animal animal = new Cat();
		if(animal instanceof Dog) {
			Dog dog = (Dog)animal;
			dog.eat();
		} 
		if (animal instanceof Cat) {
			Cat cat = (Cat)animal;
			cat.eat();
		}
	}
}

class Animal {
	public void eat() {
		System.out.print("动物能进食");
	}
}
class Dog extends Animal{
	public void eat() {
		System.out.print("狗吃狗粮");
	}
}
class Cat extends Animal {
	System.out.print("狗吃狗粮");
}

在这里插入图片描述

多态在开发中有什么作用?

降低程序耦合提高程序的扩展能力

我们以下面的一个多态的练习题为例
编写程序模拟主人喂养宠物
要求:主人有一个喂养方法feed(),可以达到喂养任何宠物的目的

public class Test {
	public static void main(String[] args){
			Dog dog = new Dog();
			Cat cat = new Cat();
			Master master = new Master();
			master.feed(dog);
			master.feed(cat);
	}
}
class Pet {
	public void eat(){}
}
class Dog extends Pet{
	public void eat(){
		System.out.println("狗吃狗粮");
	}
}
class Cat extends Pet{
	public void eat(){
		System.out.println("猫吃猫粮");
	}
}
class Master {
	public void feed(Pet pet){
		pet.eat();
	}
}

在这里插入图片描述
对于上面的代码,public void feed(Pet)使Master和Dog以及Cat之间的耦合度降低,程序扩展力变强

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值