【11】JAVASE-面向对象-多态【从零开始学JAVA】

2024-05-25 14:03:15 浏览数 (1)

Java零基础系列课程-JavaSE基础篇

Lecture:波哥

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。

五、多态

1. 现实生活中的多态

老外来访被请吃饭。落座后,一中国人说:“我先去方便一下。”老外不解,被告知“方便”是“上厕所”之意。席间主宾大悦。道别时,另一中国人对老外发出邀请:“我想在你方便的时候也请你吃饭。”老外愣了,那人接着说:“如果你最近不方便的话,咱找个你我都方便的时候一起吃。”老外倒地……

生活中的多态:同一个动作在不同的环境下的不同的状态

2.Java中的多态

​ 同一个引用类型,使用不同的实例而执行不同的操作,即父类引用指向了子类对象

多态的实现:

  1. 必须存在继承
  2. 必须存在重写
  3. 必须有父类引用指向子类对象 父类 fu = new 子类();

案例

代码语言:javascript复制
package com.bobo.oop07;

public class OOPDemo01 {

	/**
	 * 现实生活中的多态通过Java代码来实现
	 * Cut
	 * 理发师: 剪头发
	 * 医生: 动手术
	 * 演员: 暂停
	 * @param args
	 */
	public static void main(String[] args) {
		// 将一个子类的实现赋值给了一个父类的引用
		CutMan m1 = new Barber();
		CutMan m2 = new Doctor();
		CutMan m3 = new Actor();

		m1.cut();
		m2.cut();
		m3.cut();
	}

}

class CutMan{
	public void cut(){
		System.out.println("我也不知道干嘛....");
	}
}

class Barber extends CutMan{
	
	/**
	 * @Override 表示当前这个方法是一个重写的方法,
	 * 			然后会按照重写的规则来校验是否满足
	 */
	@Override
	public void cut(){
		System.out.println("理发师: 理发");
	}
}

class Doctor extends CutMan{
	
	@Override
	public void cut(){
		System.out.println("医生:动手术");
	}
}

class Actor extends CutMan{
	
	@Override
	public void cut(){
		System.out.println("演员:暂停");
	}
	
}

代码的输出:

代码语言:javascript复制
理发师: 理发
医生:动手术
演员:暂停

3. 多态访问成员的特点

​ 在多态(父类引用指向子类的实现)的情况下,我们访问引用相关的成员(成员变量,成员方法,构造方法,静态方法)时的情况

代码语言:javascript复制
父类类型  变量名 = new 子类名称();
3.1 成员变量

​ 在多态中,成员变量不存在覆盖的情况,在访问的时候是直接访问的父类中的属性(狐狸有9条命,但是能说动物有9条命吗?)

​ 编译看左边类型,运行看左边类型

3.2 成员方法

​ 在多态中,因为方法存在重写 (覆盖),所以在访问的时候执行的是子类中重写的方法

​ 编译看左边,运行看左边

3.3 构造方法

​ 先执行父类的构造方法,可以帮助我们初始化父类的成员变量,然后在执行子类的构造方法中其他的代码来实现子类成员变量的初始化。

3.4 静态成员

​ 在多态中,不会继承静态方法,因为静态方法是属于类的。所以在多态中我们调用静态方法那么执行的也是父类中的静态方法

​ 编译看左边,运行也是看左边

4.多态的好处

多态的好处:

  1. 简化代码
  2. 提高了扩展性
  3. 提高了程序的可维护性

多态的应用:

  1. 使用父类作为一个方法的形参,如果一个父类作为参数,那么我们可以传入父类对象,也可以传入对应的子类,这就是多态的常见应用
  2. 使用父类作为一个方法的返回值,暂时先不讲,在后面结合抽象类和接口统一介绍
代码语言:javascript复制
package com.bobo.oop07;

public class OOPDemo02 {

	/**
	 * 设计原则:
	 *    1.高内聚低耦合
	 *    2.对扩展开放,对修改关闭
	 *      当我们要去修改或者添加一个功能的时候,建议可以新增代码,不要去修改原有的代码
	 * @param args
	 */
	public static void main(String[] args) {
		Feeder feeder = new Feeder();
		Panda p = new Panda();
		Bamboo b = new Bamboo();
		//feeder.feederPandaEatBamboo(p, b);
		feeder.feeder(p, b);
		Tiger t = new Tiger();
		Meat m = new Meat();
		feeder.feeder(t, m);
		//feeder.feederTigerEatMeat(t, m);
		System.out.println("-------");
		Animal pig = new Pig();
		Food fodder = new Fodder();
		feeder.feeder(pig,fodder);

	}

}
// 饲养员
class Feeder{
	
	/**
	 * 给熊猫喂竹子
	 */
	/*public void feederPandaEatBamboo(Panda p,Bamboo b){
		p.show();
		b.show();
	}
	
	public void feederTigerEatMeat(Tiger t,Meat m){
		t.show();
		m.show();
	}*/
	
	/**
	 * Animal a = new Pig();
	 * Food f = new Fodder();
	 * @param a
	 * @param f
	 */
	public void feeder(Animal a,Food f){
		a.show();
		f.show();
	}
	
}

/**
 * 动物类
 * @author dpb
 *
 */
class Animal{
	
	public void show(){
		System.out.println("啥也不是...");
	}
}

class Panda extends Animal{
	
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("熊猫");
	}
}

class Tiger extends Animal{
	
	@Override
	public void show() {
		System.out.println("老虎");
	}
}

class Pig extends Animal{
	
	@Override
	public void show() {
		System.out.println("猪");
	}
}

/**
 * 食物类
 * @author dpb
 *
 */
class Food{
	public void show(){
		System.out.println("不知道什么食物");
	}
}

// 竹子类
class Bamboo extends Food{
	@Override
	public void show() {
		System.out.println("竹子");
	}
}

// 肉
class Meat extends Food{
	@Override
	public void show() {
		System.out.println("肉");
	}
}
// 饲料
class Fodder extends Food{
	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("饲料");
	}
}

5. 多态的缺点

​ 在多态中如果我们想要调用子类特有的方法及属性时是实现不了

多态中的类型转换

向上转型(自动转换) 格式:<父类型> <引用变量名> = new <子类型>(); 特点: 子类转为父类 父类的引用指向子类对象。自动进行类型转换 此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法 此时通过父类引用变量无法调用子类特有的属性和方法 向下转型(强制转换) 格式:<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>; 特点: 父类转为子类,父类引用转为子类对象。强制类型转换 在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常

代码语言:javascript复制
public static void main(String[] args) {
		Person p = new Student();
		
		p.eat();
		// 在多态中如果我们想要调用子类特有的方法实现不了
		/*Student s = new Student();
		s.study();*/
		// 强制将一个父类转换为一个子类
		Student s = (Student)p;
		s.study();
		
		NewDoctor doctor =(NewDoctor) p;
		//doctor.study();

	}

类型转换异常信息

6. instanceof关键字

​ 测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据,

记住:instanceof通常和向下转型(强制类型转换)结合使用

代码语言:javascript复制
public static void main(String[] args) {
    Person p = new Student();

    p.eat();
    // 在多态中如果我们想要调用子类特有的方法实现不了
    /*Student s = new Student();
		s.study();*/
    // 强制将一个父类转换为一个子类
    // 我们在强制类型转换之前 最好做以下类型判断 
    if(p instanceof Student){
        Student s = (Student)p;
        s.study();
    }else if(p instanceof NewDoctor){
        NewDoctor doctor =(NewDoctor) p;
        //doctor.study();
    }
}

规避 java.lang.ClassCastException异常

7.课堂练习

1.问题: 实现主人与宠物玩耍功能 和狗狗玩接飞盘游戏。 和企鹅玩游泳游戏。 编写测试类测试

代码语言:javascript复制
package com.bobo.oop07;

public class OOPDemo04 {

	/**
	 * .问题:
		实现主人与宠物玩耍功能   主人类 Master  play
		和狗狗玩接飞盘游戏。    Dog frisbee
		和企鹅玩游泳游戏。       Penguin swimming
		                 Pet 宠物类
		编写测试类测试
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Master master = new Master();
		Pet p1 = new Dog();
		master.play(p1);
		Pet p2 = new Penguin();
		master.play(p2);
	}
}

/**
 * 主人类
 * @author dpb
 *
 */
class Master{
	
	/**
	 * 和宠物游玩的方法
	 * Pet pet = new Dog();
	 * Pet pet = new Penguin();
	 */
	public void play(Pet pet){
		// 和不同的宠物玩耍,玩的方法都不相同,
		// 都是子类特有的方法,所以我们需要向下转型
		if(pet instanceof Dog){
			Dog dog = (Dog)pet;
			dog.frisbee();
		}else if(pet instanceof Penguin){
			Penguin p = (Penguin) pet;
			p.swimming();
		}
	}
}

/**
 * 宠物类
 * @author dpb
 *
 */
class Pet{
	String  name;
	
	public void eat(){
		
	}
}

class Dog extends Pet{
	
	public void frisbee(){
		System.out.println("狗狗在玩飞盘...");
	}
}

class Penguin extends Pet{
	
	public void swimming(){
		System.out.println("企鹅在游泳....");
	}
}

0 人点赞