Java面向对象三大基本特征之多态

news2024/9/27 21:23:40

多态性是面向对象编程的又一个重要特征,那么多态是什么呢?

一、多态的概念

1.概念:多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。

2.多态现实意义的理解:多态是同一个行为具有多个不同表现形式或形态的能力;多态就是同一个接口,使用不同的实例而执行不同操作。

(1)现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。                                                                                                            

(2)Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

二、多态的使用

1.多态的使用前提:

java实现多态有 3 个必要条件:继承、重写和向上转型

(1)继承:在多态中必须存在有继承关系的子类和父类。

(2)方法重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

(3)向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。即父类引用变量可以指向子类对象

父类类型 变量名=new 子类类型();

2.示例:接下来我们用代码来帮助理解

父类:Animal类

public class Animal {
	
	public String name;
	public int health;//健康值
	public int love;//亲密度
	
	public Animal() {//无参构造
		super();
	}
	public Animal(String name, int health, int love) {//有参构造
		super();
		this.name = name;
		this.health = health;
		this.love = love;
	}
	
	
	//定义一个方法
	public void test(){
		System.out.println("我是Animal类中的test()方法");
	}
	

}

子类:Cat类

public class Cat extends Animal {

	public String color;//颜色

	public Cat() {
		super();
	}

	public Cat(String name, int health, int love, String color) {
		super(name, health, love);
		this.color = color;
	}


	// 重写Animal类中的test()方法
	public void test() {
		System.out.println("我是Cat类中的test()方法");
	}
	
	public void play(){
		System.out.println("我是Cat类中的play()方法");
	}

}

子类:Dog类

public class Dog extends Animal {
	public String strain;//种类

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

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

	
	//重写Animal类中的test()方法
	public void test(){
		System.out.println("我是Dog类中的test()方法");
	}
	
	public void eat(){
		System.out.println("我是Dog类中的eat()方法");
	}
}

测试:Test类

public class Test {

	public static void main(String[] args) {
		
		//创建Dog类对象
		Dog dog = new Dog("旺财", 100, 100, "金毛");
		dog.test();
		
		//创建Cat类对象
		Cat cat = new Cat("Tom", 100, 99, "蓝色");
		cat.test();
		
		System.out.println("--------------------------");
		
		//多态:同一个父类引用,指向不同的子类实例,执行不同的操作。方法重写是实现多态的前提
		
		//向上转型(自动类型转换):父类的引用指向子类的实例(对象)
		Animal animal = new Dog("来福", 100, 98, "泰迪");
		animal.test();
		//eat()方法是Dog类中独有的方法、父类引用无法直接调用子类中特有的方法,如果父类引用需要使用子类中独有的的方法,需要将父类引用强制类型转换为子类
//		animal.eat();
		
		//向下转型(强制类型转换):子类的引用指向父类的引用
		Dog dog2=(Dog)animal;
		dog2.eat();
		
		animal = new Cat("加菲猫", 85, 88, "黄色");
		animal.test();
		//play()方法是Cat类中独有的方法,父类引用无法直接调用子类中特有的方法,如果父类引用需要使用子类中独有的的方法,需要将父类引用强制类型转换为子类
//		animal.play();
		//在向下转型过程中,容易出现类型转换异常ClassCastException,将父类引用转换成了其它的子类对象,所以在转换之前需要对父类引用类型进行判断
//		Dog cat2 =(Dog)animal;
		
		
		if(animal instanceof Dog){
			Dog dog3 =(Dog)animal;
			dog3.eat();
		}else if(animal instanceof Cat){
			Cat cat3 =(Cat)animal;
			cat3.play();
		}
		
		

	}

}

结果:

由上述代码我们可以看到,创建了一个Animal引用指向Dog类实例,然后使用animal引用调用test()方法,实际上调用的却是Dog类中的test()方法,这就是多态的一种应用;

三、Java中实现和使用多态的主要方式:

1.使用父类作为方法的形参:

示例:

父类:Animal类

public class Animal {
	private String name;
	private int health;//健康值
	private int love;

	public Animal() {
		super();
	}

	public Animal(String name, int health, int love) {
		super();
		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;
	}

	//定义一个方法实现Animal看病
	public void lookDoctor(){
		System.out.println("我是Animal类中看病的lookDoctor()方法");
	}
}

子类:Cat类

public class Cat extends Animal {
	
	private String color;

	public Cat() {
		super();
	}

	public Cat(String name, int health, int love, String color) {
		super(name, health, love);
		this.color = color;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}
	
	//重写Animal类中的lookDoctor()方法
	@Override
	public void lookDoctor() {
		System.out.println("猫生病了,打针和吃药.....");
		this.setHealth(85);
	}

}

子类:Dog类

public class Dog extends Animal {
	
	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;
	}

	//重写Animal类中的lookDoctor()方法
	@Override
	public void lookDoctor() {
		//健康值小于60的时候
		System.out.println("狗生病了,打针.......");
		this.setHealth(70);
	}
}

子类:Penguin类

public class Penguin extends Animal {

	private char sex;

	public Penguin() {
		super();
	}

	public Penguin(String name, int health, int love, char sex) {
		super(name, health, love);
		this.sex = sex;
	}

	public char getSex() {
		return sex;
	}

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

	// 重写Animal类中的lookDoctor()方法
	@Override
	public void lookDoctor() {
		// 健康值小于60的时候
		System.out.println("企鹅生病了,吃药.......");
		this.setHealth(75);
	}

}

主人类:Master类

public class Master {
	
	//定义给Animal对象看病的方法
	public void cure(Animal animal){
		//animal对象健康值小于60的时候需要看病
		if(animal.getHealth()<60){
			animal.lookDoctor();
		}
		
	}

}

测试类:Test类

public class Test {

	public static void main(String[] args) {
		
		Master master = new Master();
		
		//创建Dog类对象
		Dog dog1 = new Dog("旺财", 30, 99, "藏獒");
		System.out.println(dog1.getHealth());
		
		//调用方法原则一:方法需要什么类型的参数就需要给什么类型的参数---》方法需要什么类型的参数就需要给什么类型的参数(包括其子类)
		master.cure(dog1);
		System.out.println(dog1.getHealth());
		
		System.out.println("----------------");
		
		//创建Penguin类对象
		Penguin penguin1 = new Penguin("QQ", 45, 90, '母');
		System.out.println(penguin1.getHealth());
		
		master.cure(penguin1);
		System.out.println(penguin1.getHealth());
		
		System.out.println("----------------");
		
		Animal animal = new Dog("来福", 20, 100, "拉布拉多");
		System.out.println(animal.getHealth());
		master.cure(animal);
		System.out.println(animal.getHealth());
		
		System.out.println("---------------------------------");
		
		animal = new Penguin("QQ", 50, 92, '公');
		System.out.println(animal.getHealth());
		master.cure(animal);
		System.out.println(animal.getHealth());
	}

}

结果:

 可以看到在Master类中将Animal类对象作为一个形参,来进行方法的调用;

2.使用父类作为方法的返回值:

父类:Animal类

public abstract class Animal {
	//定义一个动物叫的方法
	public abstract void shout();

}

子类:Cat类

public class Cat extends Animal {

	@Override
	public void shout() {
		System.out.println("喵喵喵");
	}

}

子类:Dog类

public class Dog extends Animal {

	@Override
	public void shout() {
		System.out.println("汪汪汪");
	}

}

主人类:Master类

public class Master {
	//将父类Animal作为方法的形参使用,是多态的使用方式之一
	
	//定义一个方法:实现让动物叫
	public void letShout(Animal animal){
		animal.shout();
	}
	
	//将父类Animal作为方法的返回值,也是多态的使用方式之一
	public Animal giveAnimal(String type){
		Animal animal = null;
		if(type.equals("狗")){
			animal = new Dog();
		}else{
			animal = new Cat();
		}
		
		return animal;
	}

}

测试类:Test类

public class Test {

	public static void main(String[] args) {

		Master master = new Master();

		// Animal是抽象类。不能直接实例化,可以使用多态的形式,将animal引用指向子类实例
		// Animal animal = new Animal();
		Animal animal = new Dog();
		
		master.letShout(animal);
		
		animal = new Cat();
		master.letShout(animal);
		
		System.out.println("-----------------------");
		
		//赠送动物
		Scanner sc = new Scanner(System.in);
		System.out.println("你想要什么动物?(猫/狗)");
		String pet =sc.next();
		Animal ani=master.giveAnimal(pet);
		ani.shout();
	}

}

可以看到Master类中父类Animal类作为方法的返回值。

四、多态的必要性

使用多态的好处:

1.提高了代码的可维护性

2.可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

五、多态的局限性

1.当父类引用指向子类对象时,父类引用是不能直接调用子类特有的方法的。需要向下转型(强制类型转换)。

向下转型(强制类型转换)格式:

父类类型 父类对象引用=new 子类类型();//向上转型(自动类型转换):父类的引用指向子类的实例(对象

子类类型  子类对象引用=(子类类型)父类对象引用;//向下转型(强制类型转换):子类的引用指向父类的引用

向下转换后才能调用子类特有的方法。

2.同时,在向下转型的过程中,容易出现类型转换异常ClassCastException,将父类引用转换成了其它的子类对象,所以在转换之前需要对父类引用类型进行判断

这时就需要用到instanceof关键字进行判断

 if(animal instanceof Dog){
            Dog dog =(Dog)animal;
            dog.eat();//Dog类中独有方法
        }else if(animal instanceof Cat){
            Cat cat =(Cat)animal;
            cat.play();//Cat类中独有方法
        }

注意:使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类在继承上有上下级关系


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 文件操作(一) —— 遍历指定目录下的所有文件

目录 一、访问目录相关函数 1、打开/访问目录 (opendir / fdopendir) 2、读取目录内容 (readdir) 3、关闭目录 (closedir) 二、遍历指定目录下的所有文件 一、访问目录相关函数 1、打开/访问目录 (opendir / fdopendir) opendir / fdopendir 函数的作用是访问指定路径的…

工程基建--前端基建

序&#xff1a; 工程基建 &#xff1a; 编码规范、api规范、前后端协作、环境部署、微服务、微前端、性能、安全防御、统计监控、可视化 等等的建设&#xff1b; 后端基建&#xff1a; 后端规范文档、后端模板、安全、日志、微服务、RESTful API、中间件、数据库、分布式、权…

新手怎么做微信商城小程序_微信商城小程序模版哪里找

微信小程序已经在我们的生活中随处可见&#xff0c;甚至是抖音头条等其它的平台也开始做起了小程序&#xff0c;在这种情况下&#xff0c;微信小程序势必会成为未来商城的主战场之一。闻风而来想做小程序的人不少&#xff0c;而其中新手零基础也能做的小程序商城模板类工具&…

C++入门教程2||C++ 数据类型

C 数据类型 使用编程语言进行编程时&#xff0c;需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着&#xff0c;当您创建一个变量时&#xff0c;就会在内存中保留一些空间。 您可能需要存储各种数据类型&#xff08;比如字符型、宽字符型、整型…

【Leetcode】15. 三数之和

一、题目 难度不小 注意是不能重复 Python提交格式&#xff0c;返回一个list 二、暴力解法 排序 三重循环 有没有像我这样的傻子&#xff0c;三重循环&#xff0c;还没去重 后来发现要去重&#xff0c;必须要先排序&#xff0c;然后判断一下当前的数是否跟前面那个数相同&am…

SpringBoot项目如何优雅的实现操作日志记录

前言 大家好&#xff0c;我是希留。 在实际开发当中&#xff0c;对于某些关键业务&#xff0c;我们通常需要记录该操作的内容&#xff0c;一个操作调一次记录方法&#xff0c;每次还得去收集参数等等&#xff0c;会造成大量代码重复。 我们希望代码中只有业务相关的操作&…

html5期末大作业 基于HTML+CSS制作dr钻戒官网5个页面 企业网站制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Java中的多重继承问题

继承是面向对象编程 &#xff08;OOP&#xff09; 语言&#xff08;如Java&#xff09;的主要功能之一。它是一种以增强软件设计中类重用能力的方式组织类的基本技术。多重继承是众多继承类型之一&#xff0c;是继承机制的重要原则。但是&#xff0c;它因在类之间建立模棱两可的…

使用HTML实现一个静态页面(含源码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

什么密码,永远无法被黑客攻破?

在开始本文前&#xff0c;先给大家出个解谜题&#xff0c;密码是一句英文&#xff0c;开动你的脑筋吧&#xff0c;我们在本文结尾会揭晓答案&#xff1a; 密文&#xff1a;Cigumpz yin hvq se 提示&#xff1a;和身份有关的一切 说起破译密码&#xff0c;就不得不提一个人&a…

Vue3中vite.config.js文件相关配置和mock数据配置

文章目录1. vite.config.js文件相关配置2. 路径别名3. mock数据配置1. vite.config.js文件相关配置 import { defineConfig } from vite import vue from vitejs/plugin-vue import vueJsx from vitejs/plugin-vue-jsx import path from path// https://vitejs.dev/config/ ex…

简单的股票行情演示(二) - AKShare

一、概述二、环境搭建三、使用总结 1、API文档2、数据字典3、效果截图4、后台服务四、相关文章原文链接&#xff1a;简单的股票行情演示&#xff08;二&#xff09; - akshare 一、概述 上一篇文章简单的股票行情演示&#xff08;一&#xff09; - 实时标的数据中讲述了从新浪…

web前端期末大作业 HTML+CSS+JavaScript仿安踏

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 在线商城购物 | 水果商城 | 商城系统建设 | 多平台移动商城 | H5微商城购物商城项目 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&a…

连续仨月霸占牛客榜首,京东T8呕心巨作:700页JVM虚拟机实战手册

什么是Java虚拟机 虚拟机是一种抽象化的计算机&#xff0c;通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构&#xff0c;如处理器、堆栈、寄存器等&#xff0c;还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息&#xff0c…

Linux下 生成coredump文件

一. coredump文件路径 网上很多博文说到 coredump 文件默认会在默认的目录下生成。 按照网上很多的说法&#xff0c;再运行程序就会生成core文件&#xff0c;一般路径和可执行程序一个路径。 但是&#xff0c;我尝试在 ubuntu20.04系统下&#xff0c;怎么也找不到去哪里了&a…

设计模式之美——KISS、YAGNI原则

KISS 原则算是一个万金油类型的设计原则&#xff0c;可以应用在很多场景中。它不仅经常用来指导软件开发&#xff0c;还经常用来指导更加广泛的系统设计、产品设计等&#xff0c;比如&#xff0c;冰箱、建筑、iPhone 手机的设计等等。 我们知道&#xff0c;代码的可读性和可维…

ASIFT算法过程实现 --- 配置避坑指南

常规的SIFT算法进行图像匹配的时候,只能进行两个摄像机夹角比较小的(最大是15),拍摄的图像进行相机的图像匹配,但是针对于相机之间的夹脚比较大的时候,上述的算法匹配就是会出现问题.为了解决上面的这个问题,使用了一种改进的算法匹配方式ASIFT算法进行匹配.具体这种算法的优点…

MYSQL进阶(2)

删除索引:drop Index indexName on tableName; B树叶子结点和非叶子节点都存在数据&#xff0c;那么当数据量很大的时候&#xff0c;把索引加载起来就需要很长时间 联合索引: 1)定义:是给一张表上面的多个列增加索引&#xff0c;也就是说给表上面的多个列增加索引&#xff0c;供…

MongoDB聚集分析

文章目录 聚集操作管道模式聚集MapReduce 聚集简单聚集函数小结聚集操作 聚集操作是对数据进行分析的有效手段。MongoDB 主要提供了三种对数据进行分析计算的方式:管道模式聚集分析、MapReduce聚集分析、简单函数和命令的聚集分析。 管道模式聚集 这里所说的管道类似于UNIX…

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中)

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中) 1 题目 全球变暖与否? 加拿大49.6C的高温为地球北纬50以上地区创造了新的气温记录&#xff0c;一周内就有数百人死于高温;美国加利福尼亚州死亡谷54.4C&#xff0c;是地球上有记录以来的最高温度;科…