【Java基础篇 | 面向对象】--- 聊聊什么是多态(上篇)

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【JavaSE_primary】
本专栏旨在分享学习JavaSE的一点学习心得,欢迎大家在评论区讨论💌
在这里插入图片描述

目录

  • 一、什么是多态
  • 二、多态的实现条件
  • 三、重写
    • 重载和重写的方法
  • 四、向上转型和向下转型
    • 4.1向上转型
    • 4.2向下转型

一、什么是多态

多态的概念:简单来说,多态就是指同一个方法名在不同的对象上有不同的行为。

多态实现的核心概念是方法的重写和动态绑定。当子类继承父类并重写了父类的方法时,可以通过父类引用指向子类对象,并调用该方法,此时会根据对象的实际类型来决定调用哪个类的方法,从而实现多态性。

二、多态的实现条件

在java中,要实现多态的话有3个条件且这三个条件缺一不可:

1.必须是在继承体系下
2.子类必须要对父类中的方法进行重写
3.通过父类的引用调用重写的方法

那多态具体是如何体现的呢:

当传递不同类对象时,会调用对应类中的方法。

三、重写

重写概念:允许子类重新定义父类中已经存在的方法,并提供自己特定的实现。

方法重写的规则如下:

  • 子类在重写父类方法时,返回值类型、方法名、参数列表要完全相同。
  • 被重写的方法返回值类型可以不同,但是必须是具有父子类关系的。

在这里插入图片描述

  • 重写是子类对父类非private修饰、非final修饰、非构造方法等的实现过程进行重新编写。(所以如果父类的方法被private、final、static修饰的话,子类就无法对父类的方法重写。被final修饰的方法称为密封方法,不能被重写)
  • 访问权限不能比父类中被重写的方法的访问权限更低。
  • 构造方法不能被重写(构造方法只能被重载)。
  • 当子类重写父类的方法时,可以使用@Override注解来提醒编译器进行检查,确保方法名和参数正确地覆盖了父类的方法。

下面是方法重写的代码演示,请看:

class Person{public String name;public int age;Person(String name,int age){this.name = name;this.age = age;System.out.println("Person(String name,int age)");}public void fun(){System.out.println(name+",你今天开不开心");}
}
class Student extends Person {public int mark;public Student(String name,int age,int mark){super(name,age);this.mark = mark;System.out.println("Student(String name,int age,int mark)");}@Overridepublic void fun(){System.out.println(name+"今天的作业太多了,不是很开心");}
}
class Teacher extends Person{public int wages;public Teacher(String name,int age,int wages){super(name,age);this.wages = wages;System.out.println("Teacher(String name,int age,int wages");}
}
public class Test {public static void main(String[] args) {Student s1 = new Student("Daming",18,100);s1.fun();}
}

运行结果如下:
在这里插入图片描述

重载和重写的方法

重载重写
方法名称必须相同必须相同
返回值类型返回值类型不做要求返回值可以相同,但是不同时必须构成父子类关系
参数列表参数列表不同(个数、数据类型、顺序)参数列表相同
范围重载的方法要在同一个类中被重写的类和要重写的类必须构成继承关系

四、向上转型和向下转型

4.1向上转型

向上转型:创建一个子类对象,将其当成父类对象来进行使用。
语法格式:父类类型 对象名 = new 子类类型();

向上转型的使用场景有三种:直接赋值、方法传参、方法返回。

这里直接以代码进行举例了:

class Person{public String name;public int age;Person(String name,int age){this.name = name;this.age = age;System.out.println("Person(String name,int age)");}public void fun(){System.out.println(name+",你今天开不开心");}
}
class Student extends Person {public int mark;public Student(String name,int age,int mark){super(name,age);this.mark = mark;System.out.println("Student(String name,int age,int mark)");}@Overridepublic void fun(){System.out.println(name+"今天的作业太多了,不是很开心");}
}
class Teacher extends Person{public int wages;public Teacher(String name,int age,int wages){super(name,age);this.wages = wages;System.out.println("Teacher(String name,int age,int wages");}
}public class Test {public static void main(String[] args) {Student s1 = new Student("Lihua",21,150);// p1引用指向了s1Person p1 = s1;// p1.mark;  // error 无法访问,因为Person中没有mark这个属性// 这里编译的时候编译器认为是访问的Person类中的fun(),但是// 程序运行的时候访问的是子类Student中的fun()// 此过程成为动态绑定s1.fun();}
}

这里要补充动态绑定和静态绑定两个概念。

静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。

动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法。

下面代码就是向上转型的三种使用场景,请看:

class Person{public String name;public int age;Person(String name,int age){this.name = name;this.age = age;System.out.println("Person(String name,int age)");}public void fun(){System.out.println(name+",你今天开不开心");}
}
class Student extends Person {public int mark;public Student(String name,int age,int mark){super(name,age);this.mark = mark;System.out.println("Student(String name,int age,int mark)");}@Overridepublic void fun(){System.out.println(name+"今天的作业太多了,不是很开心");}
}
class Teacher extends Person{public int wages;public Teacher(String name,int age,int wages){super(name,age);this.wages = wages;System.out.println("Teacher(String name,int age,int wages)");}public void fun(){System.out.println(name+"很开心,因为今天发工资了");}
}public class Test {public static void function(Person p){p.fun();}// 向上转型方式三:返回任意子类对象public static Person function3(){return new Teacher("Simon",21,120);}public static void main(String[] args) {// 向上转型方式一:直接赋值(子类对象直接赋值给父类对象)// Person p1 = new Student("Amy",22,99);// 向上转型方式二:方法的传参过程中,也可以向上转型Student s = new Student("Sam",23,25);function(s);Teacher t = new Teacher("Tom",26,10000);function(t);}
}

运行结果如下:
在这里插入图片描述
解释在function(Person p)方法中,虽然一个引用调用一个方法,但是因为引用所引用的对象不同,导致调用这个方法所表现的行为不同。这种思想就是多态。

下面是向上转型的优缺点:

优点:让代码实现更简单灵活。
缺点::不能调用到子类特有的方法。

4.2向下转型

重要的事情放前面,向下转型是非常不安全的,所以建议平时不要使用向下转型。

示例一:

class Person{public String name;public int age;Person(String name,int age){this.name = name;this.age = age;System.out.println("Person(String name,int age)");}public void fun(){System.out.println(name+",你今天开不开心");}
}
class Student extends Person {public int mark;public Student(String name,int age,int mark){super(name,age);this.mark = mark;System.out.println("Student(String name,int age,int mark)");}public void getScore(){System.out.println("今天出成绩了");}@Overridepublic void fun(){System.out.println(name+"今天的作业太多了,不是很开心");}}
class Teacher extends Person{public int wages;public Teacher(String name,int age,int wages){super(name,age);this.wages = wages;System.out.println("Teacher(String name,int age,int wages)");}public void getWages(){System.out.println("今天发工资哈!");}public void fun(){System.out.println(name+"很开心,因为今天发工资了");}
}public class Test {public static void main(String[] args) {Person p1 = new Student("Donghua",21,112);// p1.getScore //error 因为这里只能访问Person类自己特有的方法Student s1 = (Student)p1;s1.getScore(); //这里通过s1可以访问getScore方法}
}

这里把Person类型强转为子类Student类型。

示例二:向下转型是指将父类类型的引用转换为子类类型的引用。在向下转型的过程中,需要确保原始对象的实际类型是转换后的子类类型,否则会抛出ClassCastException异常。

请看代码:

class Person{public String name;public int age;Person(String name,int age){this.name = name;this.age = age;System.out.println("Person(String name,int age)");}public void fun(){System.out.println(name+",你今天开不开心");}
}
class Student extends Person {public int mark;public Student(String name,int age,int mark){super(name,age);this.mark = mark;System.out.println("Student(String name,int age,int mark)");}public void getScore(){System.out.println("今天出成绩了");}@Overridepublic void fun(){System.out.println(name+"今天的作业太多了,不是很开心");}}
class Teacher extends Person{public int wages;public Teacher(String name,int age,int wages){super(name,age);this.wages = wages;System.out.println("Teacher(String name,int age,int wages)");}public void getWages(){System.out.println("今天发工资哈!");}public void fun(){System.out.println(name+"很开心,因为今天发工资了");}
}public class Test {public static void main(String[] args) {Person p1 = new Student("Jame",21,115);Teacher t1 = (Teacher)p1;t1.getWages();}
}

示例二运行结果如下:
在这里插入图片描述

示例二解释首先创建了一个Student对象,并将其赋值给了一个Person类型的变量p1。这是一种向上转型的操作,可以安全地进行,因为Student是Person的子类。

接着尝试将p1向下转型为Teacher类型,即将其赋值给一个Teacher类型的变量t1。这是一种不安全的操作,因为p1实际上是Student类型的对象。运行这段代码会抛出ClassCastException异常。

示例二解决方式,请看代码:

Person p1 = new Student("Jame", 21, 115);
if (p1 instanceof Teacher) {Teacher t1 = (Teacher) p1;t1.getWages();
} 
else {System.out.println("p1不是Teacher类型的对象");
}

好了,以上就是本文的全部内容啦,就到这里吧!!!
再见啦友友们!!!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023/9/8 -- C++/QT

作业 1> 自行封装一个栈的类,包含私有成员属性:栈的数组、记录栈顶的变量 成员函数完成:构造函数、析构函数、拷贝构造函数、入栈、出栈、清空栈、判空、判满、获取栈顶元素、求栈的大小 02stack.h: #ifndef __02STACK_H__ #define __…

【收藏】编译 WRF 步骤指导,安装、运行 WRF 和 WPS

本文旨在编译 WRF 步骤的指导。它将引导初级用户完成确保计算机环境设置正确、测试组件及其相互兼容性、然后安装 WRF 和 WPS 的过程,最后获得一些准备运行 WPS 和 WRF 的指导。 单击下面的选项卡进行快速导航。如果您是初学者,建议从头开始并完成每个步…

使用IO操作文件

一、File类操作文件或目录 1.File操作文件或目录 java.io.File 类是文件和目录 路径名 的抽象表示,主要用于文件和目录的创建、查找和删除等操作。 Java虚拟机中的一个 File 实例表示一个路径,这个路径可能对应一个文件或一个目录。 File 类的实例所表…

嵌入式面试/笔试C相关总结

1、存储 单片机端编译后分为code ro rw zi几个区域,其中code是执行文件,ro(read only)只读区域,存放const修饰常量、字符串。rw(read write)存放已初始化变量。zi存放未初始化变量。编译完成后bin大小为coderorw。运行时所需内存为rwzi。 在电…

SQL7 查找年龄大于24岁的用户信息

描述 题目:现在运营想要针对24岁以上的用户开展分析,请你取出满足条件的设备ID、性别、年龄、学校。 用户信息表:user_profile iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543female20…

C语言数组和指针笔试题(二)(一定要看)

目录 字符数组二例题1例题2例题3例题4例题5例题6例题7总结 字符数组三例题1例题2例题3例题4例题5例题6例题7 字符数组二 char arr[] {a,b,c,d,e,f} 1:printf("%d\n", strlen(arr)); 2:printf("%d\n", strlen(arr0)); 3:printf("%d\n", strlen(…

Promethues(五)查询-PromQL 语言-保证易懂好学

一、介绍 普罗米修斯提供了一种称为PromQL(普罗米修斯查询语言)的函数式查询语言,允许用户实时选择和聚合时间序列数据。 表达式的结果可以显示为图形,在 Prometheus 的表达式浏览器中显示为表格数据,也可以通过 HTT…

Linux HTTP协议

目录 1.浏览器与服务器通信过程2.HTTP请求报头(1)HTTP的请求报头结构(2)HTTP的请求方法 3.HTTP应答报头(1)HTTP的应答报头结构(2) HTTP的应答状态 1.浏览器与服务器通信过程 浏览器…

PaddleOCR学习笔记1-初步尝试

尝试使用PaddleOCR方法,如何使用自定义的模型方法,参数怎么配置,图片识别尝试简单提高识别率方法。 目前仅仅只是初步学习下如何使用PaddleOCR的方法。 一,测试识别图片: 1.png : 正确文本内容为“哲学可以帮助辩别现…

领域驱动设计:领域模型与代码模型的一致性

文章目录 领域对象的整理从领域模型到微服务的设计领域层的领域对象应用层的领域对象 领域对象与微服务代码对象的映射典型的领域模型非典型领域模型 DDD 强调先构建领域模型然后设计微服务,以保证领域模型和微服务的一体性,因此我们不能脱离领域模型来谈…

HarmonyOS Codelab 优秀样例——溪村小镇(ArkTS)

一、介绍 溪村小镇是一款展示溪流背坡村园区风貌的应用,包括园区内的导航功能,小火车行车状态查看,以及各区域的风景展览介绍,主要用于展示HarmonyOS的ArkUI能力和动画效果。具体包括如下功能: 打开应用时进入启动页&a…

EasyPHP-Devserver-17安装和配置mantisBT

文章目录 1、准备工作2、安装easyphp2.1 http://127.0.0.1 无法访问 3、安装mantisBT和phpMyAdmin3.1 配置浏览器的访问url和端口号(配置局域网内可访问)3.2 安装mantis 4、Administrator 注册新用户时设置登录密码5、附件上传6、邮件配置 文章参考自&am…