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

news2025/1/20 5:57:37

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【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)");
    }

    @Override
    public 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)");
    }

    @Override
    public 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引用指向了s1
        Person 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)");
    }

    @Override
    public 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("今天出成绩了");
    }

    @Override
    public 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("今天出成绩了");
    }

    @Override
    public 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.coloradmin.cn/o/1007547.html

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

相关文章

【操作系统】聊聊进程是如何调度的

进程的引入是为了让操作系统可以同时执行不同的任务。而进程从创建到销毁也就对应不同的状态,进程状态,本质上就是为了用有限的计算机资源合理且高效地完成更多的任务 而不同的任务如何进行合理的分配,被CPU执行,其实就是不同的调…

网工内推 | 国企网络运维,大专以上即可,有厂商认证优先

01 北京新明星电子技术开发有限公司 招聘岗位:运维工程师 职责描述: 1、负责所在特定客户的技术支持服务工作,负责各厂商服务器、存储设备的日常操作、系统升级、故障处理工作。 2、对运维工作进行总结、提出问题或隐患,给出建议…

进程地址空间(Linux虚拟内存机制)

文章目录 一.Linux进程地址空间的结构二.Linux管理进程地址空间的方式三.Linux进程使用物理内存的模型四.进程地址空间的存在意义 本章理论基于32位平台的Linux–kernel 2.6.32版本内核 一.Linux进程地址空间的结构 为了保证内存安全,现代操作系统不允许应用程序(进程)直接访问…

计算机毕业设计 高校普法系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

深入解析 qsort 排序(上),它为什么是万能排序?

前言:对于库函数有适当了解的朋友们,对于 qsort 函数想必是有认知的,因为他可以对任意数据类型进行排序的功能属实是有点厉害的,本次分享,笔者就给大家带来 qsort 函数的全面的解读 本次知识的分享笔者分为上下俩卷文章…

[Java]JDK8新特性

一、Java版本迭代概述 1.1发布特点(小步快跑,快速迭代) 发行版本发行时间备注Java 1.01996.01.23Sun公司发布了Java的第一个开发工具包Java 5.02004.09.30①版本号从1.4直接更新至5.0;②平台更名为JavaSE、JavaEE、JavaMEJava 8…

一些docker笔记

一些docker笔记 docker是一个跨平台,可迁移的应用虚拟化,容器化服务平台Docker口号1:Build,Ship and Run (构建,发送和运行) Docker口号2: Build once,Run anywhere (构建一次,到处能用)docker一些概念 docker仓库 官方有dockeHu…

Linux命令200例:expr一个用于进行数值表达式求值的工具

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师&#xff0…

网站文章生成技术-网站文章生成工具免费

大家好,今天我想和大家分享一些关于网站文章生成的疑虑和期待。作为一个常常需要在网站上发布文章的人,我对这项技术的发展充满了好奇和担忧。在这篇文章中,我将坦率地表达我的想法,希望能引发一些思考。 让我谈一谈我的疑虑。网站…

Python 图形化界面基础篇:使用网格布局( Grid Layout )排列元素

Python 图形化界面基础篇:使用网格布局( Grid Layout )排列元素 引言什么是 Tkinter 的网格布局?步骤1:导入 Tkinter 模块步骤2:创建 Tkinter 窗口步骤3:创建网格步骤4:将元素放置在…

天线原理【1】 天线辐射的物理过程

1 前言 前面讲以振子方程入手分析电磁场问题的解的时候,有网友发信息说这和天线有什么关系,怎么从振子入手分析天线; 那我就开始写几次关于天线的。 有一种说法是,能给任何人讲懂的理论,才说明你真的懂了。 对天线部…

Dbeaver自动换行

Dbeaver自动换行 自己最近在使用dbeaver进行SQL语句的执行,发现,SQL语句太长不能自动换行,要拖很久,很麻烦 工具嘛,就是要顺我心意,不然用着多没意思!话不多说,上代码! 就设置下,自动换行 操作步骤 1.点击编辑 2.选择格式 3.第三步如上所示 到这一步,dbeaver的自动换行就完成,…

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

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

LeetCode(力扣)134. 加油站Python

LeetCode134. 加油站 题目链接代码 题目链接 https://leetcode.cn/problems/gas-station/description/ 代码 class Solution:def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:cursum 0minfuel float(inf)for i in range(len(gas)):rest gas[i…

leetcode刷题_栈相关_c++版

(1)225用栈实现队列–简单 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现 MyStack 类: void push(int x) 将元素 …

任务长期不释放和占用单节点持续的cpu,导致hivesever2本身内存泄漏造成

任务长期不释放和占用单节点持续的cpu,导致hivesever2本身内存泄漏造成 产生的原因在于: 查询过于复杂或者数据量过大:当有复杂的查询或处理大量数据的请求时,HiveServer2可能会出现高负载。这可能涉及大量的计算、IO操作或涉及大…

支付宝小程序排名优化,一个小白的成长手记

那是一个风和日丽的周末早上,阳光透过窗帘洒进屋内,温暖了我的双脚。这是我加入新公司的第一个周末,我坐在桌前,满怀激情地准备开发我的第一个支付宝小程序。【名即薇】 经过两天两夜的奋战,我终于完成了一个初版的支付宝小程序。是一个集美食资讯、餐厅点评、外卖订餐于一体的…

Springboot整合整合Swagger3

常用注解 Api:用在请求的类上,表示对类的说明 tags“说明该类的作用,可以在UI界面上看到的注解”value“该参数没什么意义,在UI界面上也看到,所以不需要配置” ApiOperation:用在请求的方法上,…

【嵌入式】化繁为简 UART、I2C、SPI整理

本文参考:浅谈单片机通信,化繁为简UART、I2C、SPI学习全家桶,你值得拥有!_哔哩哔哩_bilibili 单片机的数据都是以0、1发送的,每一位发送多少时间取决于波特率 。 波特率是发送二进制数据位的速率,单位是b…

认识数据分析

文章目录 1. 认识数据分析1.1 数据自身的三大属性1.2 建数仓 数据分析的工程技术1.3 数据分析解决问题的原理1.4 数据分析的具体流程1.5 数据的中心化和智能化1.6 数据分析的四种类型和六个方向 1. 认识数据分析 1.1 数据自身的三大属性 客观:用数字衡量和表现一件…