面向对象之多态

本文深入探讨了面向对象编程中的多态性概念,从生活中的例子出发解释了多态的含义。在Java中,多态体现在继承关系、方法重写以及父类引用指向子类对象。文章详细阐述了实现多态的必要条件,如继承、重写和父类引用,并通过代码示例展示了多态访问成员变量和方法的行为。同时,文章指出了多态带来的简化代码、提高维护性和扩展性的优点,以及可能存在的问题和解决方案,包括向下转型、类型转换异常及其处理方式。最后,文章提到了多态与开闭原则的关系,并提出了在遇到父类引用为Object时可能的安全隐患和泛型的潜在解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向对象之多态

先给大家讲个笑话
在这里插入图片描述
多态的引入:
生活中的多态
在生活中我们听到“打”一声可能只是 击,敲,攻击的意思,但是其实在不同的环境下,打的意思非常多。
例如:打车,打电话,打雷,打证明,打包裹

多态的概述
生活中: 同一个动作在不同环境下表现出来的不同状态
Java中: 同一个方法在不同的对象中体现出来不同的状态
内存中: 父类引用指向子类对象

多态的实现的必要条件:(重点要记下)
1.存在继承关系
2.存在方法重写
3.父类引用指向子类对象

先给个小例子代码如下所示:

public class DuoTaiDemo01 {
	public static void main(String[] args) {
		Man m = new Doctor();
		m.cut();
		
		m = new Director();
		m.cut();
		
		m = new Hairdresser();
		m.cut();
	}
}

class Man {
	public void cut() {
		System.out.println("我是man, 我也不知道怎么cut");
	}
}

class Doctor extends Man {
	public void cut() {
		System.out.println("动手术");
	}
}

class Director extends Man {
	@Override
	public void cut() {
		System.out.println("暂停");
	}
}

class Hairdresser extends Man {
	@Override
	public void cut() {
		System.out.println("剪头发");
	}
}

多态访问成员的特点:
Father father = new Son()
左边类型 ————右边类型
成员变量:
1.编译时期看左边的类型,如果左边类型中没有变量,编译报错
2.运行时期看左边类型,左边类型的变量的值就是运行的结果
3.编译看左边,执行看左边
成员方法:
编译看左边,执行看右边
构造方法:
1.多态访问子类构造方法会先访问父类构造方法
2.帮助子类初始化父类继承过来的成员
静态方法:
编译看左边,执行看左边

举例代码如下:

public class DuoTaiDemo02 {
	public static void main(String[] args) {
		Fu fu = new Zi();
		System.out.println(fu.num); // 10
		fu.method();
		
		fu.show();
	}
}

class Fu {

	int num = 10;

	public void method() {
		System.out.println("Fu.method()");
	}
	
	public static void show() {
		System.out.println("Fu.show");
	}
}

class Zi extends Fu {

	int num = 20;

	@Override
	public void method() {
		System.out.println("Zi.method()");
	}
	
	public static void show() {
		System.out.println("Zi.show");
	}
	
}

多态的优点
1.简化了代码
2.提高了维护性和扩展性

//饲养员给不同的动物喂不同的食物
public class DuoTaiDemo03 {
	public static void main(String[] args) {
		Feeder f = new Feeder();
		Meat m = new Meat();
		m.setName("五花肉");
		
		Tiger t = new Tiger();
		t.setName("东北虎");
//		f.feedMeatToTiger(m, t);
		f.feed(m, t);
		
		Bamboo b = new Bamboo();
		b.setName("大竹子");
		Panda p = new Panda();
		p.setName("大熊猫");
//		f.feedBambooToPanda(b, p);
		f.feed(b, p);
		
		Food food = new Banana();
		food.setName("香蕉");
		
		Animals an = new Monkey();
		an.setName("猴子");
		f.feed(food, an);
	}
}

//开闭原则: 对扩展开放,对修改关闭
class Feeder{
	// 给老虎喂肉
//	public void feedMeatToTiger(Meat m, Tiger t) {
//		m.show();
//		t.show();
//	}
	
	// 熊猫喂竹子
//	public void feedBambooToPanda(Bamboo b, Panda p) {
//		b.show();
//		p.show();
//	}
	
	// 利用多态
	/*
	 * Food f = new Meat();
	 * Animals a = new Tiger();
	 */
	public void feed(Food f, Animals a) {
		f.show();
		a.show();
	}
}

class Animals{
	
	public String name;
	
	public void show() {
		System.out.println("我是动物");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

class Monkey extends Animals {
	@Override
	public void show() {
		System.out.println("我是" + getName());
	}
}

class Banana extends Food {
	@Override
	public void show() {
		System.out.println("我是" + getName());
	}
}

class Bear extends Animals{
	@Override
	public void show() {
		System.out.println("我是" + name);
	}
}

class Tiger extends Animals{
	@Override
	public void show() {
		System.out.println("我是" + name);
	}
}

class Panda extends Animals{
	@Override
	public void show() {
		System.out.println("我是" + name);
	}
}


class Food{
	
	public String name;
	
	public void show() {
		System.out.println("我是食物");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}

class Meat extends Food{
	public void show() {
		System.out.println("我是" + name);
	}
}

class Bee extends Food{
	@Override
	public void show() {
		System.out.println("我是" + name);
	}
}

class Bamboo extends Food{
	public void show() {
		System.out.println("我是" + name);
	}
}

多态的缺点:
使用父类引用无法访问子类所特有的方法
解决办法: 向下转型

基本类型存在自动类型转换和强制类型转换
引用类型存在向上转型和向下转型

向上转型(自动转换)
格式:<父类型> <引用变量名> = new <子类型>();
特点:
子类转为父类 父类的引用指向子类对象。可以理解为自动进行类型转换(和自动类型转换完全是两个概念)
此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法
此时通过父类引用变量无法调用子类特有的属性和方法

向下转型(强制转换)
格式:<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;
特点:
父类转为子类,父类引用转为子类对象。可以理解为强制类型转换
在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常

异常名称: 类型转换异常 java.lang.ClassCastException
产生原因: 在向下转型的过程中,没有转换成真实的类型
解决办法: 在每次向下转型之前做一个类型的判断

类型判断的语法: instanceof
左边对象 instanceof 类名 这个表达式的结果是boolean类型
测试它左边的对象是否是它右边的类的实例

多态的弊端可以使用instanceof关键字+向下转型来解决
我们知道我们需要对父类的所有子类做逐一判断,违背了开闭原则
为了开闭原则我们还是可以继续开发,但是如果这个父类引用是Object呢?
无法做逐一个判断,安全隐患一致存在,可以考虑是泛型。

举例1代码如下所示:

public class DuoTaiDemo04 {
	public static void main(String[] args) {
//		Car c = new BMW();
//		c.run();
		
		// 想要访问BMW的fillOil,无法访问
		// 利用向下转型
//		BMW bmw = (BMW) c;
//		bmw.fillOil();
//		
//		c = new Benz();
//		c.run();
		
//		Benz benz = (Benz) c;
//		benz.leakOli();
		
//		BMW bmw2 = (BMW) c;
//		bmw2.fillOil();
		
//		System.out.println(c instanceof BMW);
//		System.out.println(c instanceof Benz);
		Car c = new Benz();
		c.run();
		
		c = new BYD();
		c.run();
		
		if (c instanceof Benz) {
			Benz benz = (Benz) c;
			benz.leakOli();
		} else if (c instanceof BMW) {
			BMW b = (BMW) c;
			b.fillOil();
		} else  if (c instanceof BYD) {
			BYD byd = (BYD) c;
			byd.electric();
		}
		
		Object obj = new BMW();
		
	}
}

class Car {
	public void run() {
		System.out.println("Car.run()");
	}
}

class BMW extends Car {
	@Override
	public void run() {
		System.out.println("BMW.run()");
	}
	
	public void fillOil() {
		System.out.println("加油");
	}
}

class Benz extends Car {
	@Override
	public void run() {
		System.out.println("Benz.run()");
	}
	
	public void leakOli() {
		System.out.println("漏油");
	}
}

class BYD extends Car {
	@Override
	public void run() {
		System.out.println("BYD.run()");
	}
	
	public void electric() {
		System.out.println("充电");
	}
}

举例2代码如下所示:

/*
	实现主人与宠物玩耍功能 play
	和狗狗玩接飞盘游戏。
	和企鹅玩游泳游戏。
	编写测试类测试
	分析:
		给Dog添加接飞盘方法catchingFlyDisc( )
		给Penguin添加游泳方法swimming( )
		给主人添加play(Pet pet)方法 sendPet(Pet pet)
	思考:如果还需要再主人类中添加赠送宠物的方法呢?
 */
public class DuoTaiDemo05 {
	public static void main(String[] args) {
		Hoster hoster = new Hoster(5, 3, "老王");
		hoster.play(new Dog());
		hoster.play(new Penguin());
		
		hoster.sendPet(new Dog());
		hoster.sendPet(new Dog());
		hoster.sendPet(new Dog());
		hoster.sendPet(new Dog());
		hoster.sendPet(new Dog());
		hoster.sendPet(new Dog());
		
		System.out.println(hoster.getPenguinCount());
		hoster.sendPet(new Penguin());
		hoster.sendPet(new Penguin());
		hoster.sendPet(new Penguin());
		hoster.sendPet(new Penguin());
	}
}

class Hoster {

	private int dogCount;
	private int penguinCount;
	private String name;

	public Hoster() {
		super();
	}

	public Hoster(int dogCount, int penguinCount, String name) {
		super();
		this.dogCount = dogCount;
		this.penguinCount = penguinCount;
		this.name = name;
	}

	public void play(Pet pet) {
		pet.play();

		if (pet instanceof Dog) {
			Dog dog = (Dog) pet;
			dog.catchingFlyDisc();
		} else if (pet instanceof Penguin) {
			Penguin penguin = (Penguin) pet;
			penguin.swimming();
		}
	}

	public void sendPet(Pet pet) {
		if (pet instanceof Dog) {
			dogCount --;
			
			if (dogCount < 0) {
				dogCount = 0;
			}
			System.out.println("还剩下" + dogCount + "只狗!!!");
		} else if (pet instanceof Penguin) {
			penguinCount --;
			
			if (penguinCount < 0) {
				penguinCount = 0;
			}
			System.out.println("还剩下" + penguinCount + "只企鹅!!!");
		}
	}

	public int getDogCount() {
		return dogCount;
	}

	public void setDogCount(int dogCount) {
		this.dogCount = dogCount;
	}

	public int getPenguinCount() {
		return penguinCount;
	}

	public void setPenguinCount(int penguinCount) {
		this.penguinCount = penguinCount;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

class Pet {
	public void play() {
		System.out.println("Pet.play()");
	}
}

class Dog extends Pet {
	public void play() {
		System.out.println("Dog.play()");
	}

	public void catchingFlyDisc() {
		System.out.println("Dog.catchingFlyDisc()");
	}
}

class Penguin extends Pet {
	@Override
	public void play() {
		System.out.println("Penguin.play()");
	}

	public void swimming() {
		System.out.println("Penguin.swimming()");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值