16.多态

1.什么是多态

生活中的多态:同一种事物,由于条件的不同,产生的结果也不同。

多态:同一个引用类型,使用不同的实例而执行不同的操作。

1.1 认识多态

1、多态的通常含义是指能够呈现出不同的形式或者形态;

2、在程序设计中,多态意味着一个特定类型的变量可以引用不同类型的对象,并且自动的调用引用的对象的方法,也就是说,根据不同的引用的对象的类型,执行不同的操作;

3、方法重写是实现多态的基础

4、多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量的类型决定的。

当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写过的方法。

1.2 向上转型

什么是向上转型:子类向父类的转换称为向上转型,即:父类的引用对象指向子类对象,是自动类型转换

语法格式:父类名  父类对象=new 子类型();

注:

此时通过父类引用变量调用的方法是子类覆盖或继承了父类的方法,并不是父类的方法;

此时通过父类引用变量无法调用子类特有的方法。

1.3 向下转型

概念:将一个指向子类对象的父类引用赋给一个子类的引用,即将父类类型转换为子类类型,是强制类型转换。

语法格式:子类型  引用变量名=(子类型)父类引用变量;

1.4 instanceof运算符

1、在向下转型的过程中,如果不是转换为真实子类类型,会出现类型转换异常ClassCastException)。

2、在Java中提供了instanceof运算符类进行类型的判断。

3、使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误。

4、instanceof通常和强制类型转换结合使用。

1.5 多态的优势

->可替换性:多态对已存在的代码具有可替换性。

-->可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特征的运行和操作。实际上新加子类更容易获得多态功能。

-->接口性:多态是父类向子类提供了一个共同接口,由子类来具体实现。

-->灵活性:多态在应用中体现了灵活多样的操作,提高了使用效率。

-->简化性:多态简化了应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

2.抽象方法和抽象类

2.1 抽象方法

在Java中,当一个类的方法被abstract关键字修饰时,这个方法称之为抽象方法。

语法格式:访问修饰符 abstract 返回值类型 方法名(参数列表);

访问修饰符,参数列表根据需要可写可不写。

特点:

1.抽象方法没有方法体;

2.抽象方法所在的类必须定义为抽象类;

3.抽象方法在子类中必须要重写,如果这个子类不重写这个抽象方法,则这个子类要定义为抽象类。

注:

private关键字不能用来修饰抽象方法;

abstract修饰符不能和final修饰符一起使用。

2.2 抽象类

在Java中,当一个类被abstract关键字修饰时,该类称之为抽象类。

语法格式:abstract  class 类名{

                代码

}

说明:

抽象类需要用修饰符abstract修饰,普通类不需要。

1.普通类可以实例化,抽象类不能被实例化。

2.抽象类中可以有抽象方法也可以没有抽象方法,可以有普通方法也可以没有普通方法。

3.抽象类中可以包含普通类包含的一切成员。

当一个类实例化没有意义时,就可以把这个类定义为抽象类。

3.多态的举例说明

需求:使用多态实现主人领养动物并带动物看病的功能,狗有特有的吃方法,企鹅有特有的游泳方法。

1.编写父类

//编写父类
public class Animal {
	private String name;
	private int health;
	private int love;

	public Animal() {

	}

	public Animal(String name, int health, int love) {
		this.name = name;
		this.health = health;
		this.love = love;
	}

	public String getName() {
		return name;
	}

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

	public int getHealth() {
		return health;
	}

	public void setHealth(int health) {
		this.health = health;
	}

	public int getLove() {
		return love;
	}

	public void setLove(int love) {
		this.love = love;
	}
	
	public void toHospital(){
		System.out.println("去看病");
	}
}

2.编写子类

//编写子类Dog,通过关键字extends继承父类Animal
public class Dog extends Animal {
	// 声明品种属性,这个属性是Dog类特有的
	private String strain;

	public Dog() {
		super();// 表示调用父类Animal类的无参构造方法
	}

	public Dog(String name, int health, int love, String strain) {
		super(name, health, love);// 表示调用父类Animal类中的有参构造方法
		this.strain = strain;
	}

	public String getStrain() {
		return strain;
	}

	public void setStrain(String strain) {
		this.strain = strain;
	}

	//Dog类重写的toHospital()看病方法
	public void toHospital() {
		System.out.println("打针");
		this.setHealth(80);
	}
	//Dog类特有的eat()方法
	public void eat() {
		System.out.println("狗喜欢吃骨头");
	}
}
//编写子类Penguin类,继承父类Animal类
public class Penguin extends Animal {
	
	// Penguin类特有属性
	private String sex;
	// 无参构造方法
	public Penguin() {
		super();
	}
	// 有参构造方法
	public Penguin(String name, int health, int love, String sex) {
		super(name, health, love);
		this.sex = sex;
	}
	//sex读写方法
	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	//Penguin类重写的toHospital()看病方法
	public void toHospital() {
		System.out.println("打针,吃药");
		this.setHealth(90);
	}
	//Penguin类特有的swimming()方法
	public void swimming(){
		System.out.println("企鹅会仰泳");
	}
}

3.编写主人类,定义看病方法

//编写主人类,在这个类中定义看病方法
public class Master {
	//定义看病方法
	public void cure(Animal animal){
		//如果animal的健康值低于60,就去看病
		if(animal.getHealth()<60){
			animal.toHospital();
		}
	}
}

4.进行测试

public class Test {

	public static void main(String[] args) {
		// 创建主人类对象
		Master master = new Master();

		// 向上转型:父类引用指向子类的实例(对象),即子类向上转型了
		// 父类引用animal指向子类Dog类对象
		Animal animal = new Dog("富贵", 30, 98, "金毛");
		System.out.println("看病前健康值:" + animal.getHealth());

		// 调用看病方法,此时的animal指向Dog类,进而调用Dog类的看病方法toHospital()方法
		master.cure(animal);
		System.out.println("看病后健康值:" + animal.getHealth());
		// 但是父类引用不能调用子类的特有方法和属性
		// animal.eat();
		// animal.getStrain();
		
		// 向下转型:子类的引用(对象名)指向父类引用(对象名),即父类向下转型,需要强制类型转换
		Dog dog = (Dog) animal;
		dog.eat();// 调用Dog类的特有方法eat()方法
		System.out.println("狗的品种:" + dog.getStrain());

		System.out.println("----------------");
		
		// 父类引用指向子类Penguin类对象
		animal = new Penguin("qq", 40, 99, "公");
		System.out.println("看病前健康值:" + animal.getHealth());
		// 调用看病方法,此时的animal指向Penguin类,进而调用Penguin类的看病方法toHospital()方法
		master.cure(animal);
		System.out.println("看病后健康值:" + animal.getHealth());
		//下面两行代码在编写时不会报错,但是运行会报错,因为此时的父类引用指向的是子类Penguin类对象,向下转型时却没有转换成其指向的子类
		/*Dog dog1=(Dog)animal;//ClassCastException类型转换异常,父类引用没有转换成其指向的子类
		dog1.eat();*/
		
		/*由此可见:
		 * 在向下转型的时候,有可能转换错误,没有转换成其指向的子类,这时候会报ClassCastException异常
		 * 我们可以在转型之前使用instanceof关键字进行判断父类引用指向了哪个子类对象 
		 */
		if(animal instanceof Dog){
			Dog dog1=(Dog)animal;
			dog1.eat();
		}else if(animal instanceof Penguin){
			Penguin pe1=(Penguin)animal;
			pe1.swimming();
		}
	}
}
根据JavaJavaScript,mysql,c语言,vue3,回答下列问题 1.什么是面向对象编程? 2.Java中的集合包括什么? 3.spring boot三个架构? mapper的作用 4.Mybatis mapper.xml的配置映射 5.Radis 数据结构 6.Redis数据一致性问题 7.Mysql 数据结构 char和varchar的区别 8.Vue生命周期,钩子函数,响应式变量,npm,常用的element -ui 9.springboot常用注解有哪些 10.Nnginx 11.Rocketmq消息延迟 12.Mybatis用法 13.Arralist用过哪些api 14.遍历集合有哪几种 15.MySQL数据类型用过哪些 16.Date和datetime的区别 17.Git常见命令 18.Html标签通常有哪些 css 19.数据采集与分析用的哪个库 20.可视化用的什么技术 21.拦截器 22.常见异常 23.事务 24.组件通信,父组件如何给子组件传递信息 25.路由组件 26.反射 27.线程池,多线程 28.什么是注解(标记) 29.Aop 30.Git 31.idea常用插件 32.什么是反向代理 33.第三方接口 34.Lombok用法 35.Vue3常用的api 36.vue3的常用生命周期 37.Vue router 38.遍历数组的方法 39.Foreach和map的区别(有返回值) 40.Radis数据类型? 41.多态 42.Hashmap遍历方式 43.Springboot配置文件的相关知识 44.前端三件套 45.数据库与其外键的主要内容 46.常见表的关系 47.若依框架 48.Nginx相关内容与配置文件 49.Linux命令 50.后端接口怎么定义的 51.前端如何搭建 52.数据库常见的相关命令语句 53.数据库表设计 54.V-if 55.V-show
04-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值