【一步一步了解Java系列】:重磅多态

看到这句话的时候证明:此刻你我都在努力
加油陌生人
微信图片编辑_20240229212205.png

个人主页:Gu Gu Study
专栏:一步一步了解Java

喜欢的一句话: 常常会回顾努力的自己,所以要为自己的努力留下足迹


喜欢的话可以点个赞谢谢了。
作者:小闭


何为多态

在Java中,多态(Polymorphism)是一种允许不同类的对象对同一消息做出响应的能力,即同一个接口可以被不同的实例以不同的方式实现。多态性是面向对象编程的一个核心概念,它使得代码更加灵活和可扩展。
多态性主要通过以下几种方式实现:

  1. 方法重载(Overloading):这是编译时多态的一个例子。方法重载允许同一个类中有多个同名方法,只要它们的参数列表不同(参数的类型、数量或顺序不同)。
  2. 方法重写(Overriding):这是运行时多态的一个例子。当子类继承父类时,子类可以重写父类的方法。如果子类对象调用了一个被重写的方法,将执行子类中的方法实现,而不是父类中的实现。
  3. 接口实现:一个类可以实现一个或多个接口,接口定义了一组方法规范,具体的实现类必须提供这些方法的具体实现。不同的实现类可以以不同的方式实现同一个接口中定义的方法。
  4. 抽象类:抽象类可以包含抽象方法,这些方法没有具体的实现,必须由继承抽象类的子类来实现。这也是一种多态的体现,因为不同的子类可以提供不同的实现。

多态的使用可以带来以下好处:

  • 代码复用:通过继承和接口实现,可以减少代码的重复编写。
  • 扩展性:通过多态,可以在不修改现有代码的情况下,引入新的类和对象。
  • 灵活性:多态允许程序在运行时动态地绑定方法调用,使得程序更加灵活。

多态是Java中实现开闭原则(对扩展开放,对修改封闭)的关键机制之一,它允许程序更容易适应变化,同时保持代码的稳定性和可维护性。
多态实现的条件:

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

总的来说:多态即是不同对象,不同的的态度。


方法重载的多态

方法重载在前面其实已经说过了,下面是一个方法重载多态的情况:

public class Cat {String type="猫咪";public void eat(){System.out.println(type+"吃猫粮");}public void eat(int n){System.out.println(type+"吃"+n+"两猫粮");}}class Test{public static void main(String[] args) {Cat cat=new Cat();cat.eat();cat.eat(1);}}

image.png
上面我们对方法进行重载,然后传参不同时,同一个方法却呈现不同的打印方式即(不同的形态)。

方法重写的多态

我们先要认识,何为重写
在Java中,重写(Overriding)是指子类提供一个特定的实现,覆盖从父类继承来的方法的实现。这是运行时多态的一个体现,意味着在程序运行时,会根据对象的实际类型来调用相应的方法。
要实现方法重写,需要满足以下条件:

  1. 方法名、参数列表和返回类型:子类重写的方法必须具有与父类被重写方法相同的方法名、参数列表和返回类型。如果返回类型不同,则不是重写,而是重载(Overloading)。
  2. 访问权限:子类重写的方法不能具有比父类更严格的访问权限。例如,如果父类中的方法是public的,子类重写的方法也必须是public或protected,但不能是private。
  3. 非静态方法:重写必须发生在非静态方法上。静态方法(Static methods)不能被重写。
  4. 非最终方法:如果父类中的方法是final的,则不能被重写。

下面是一个简单的示例,展示如何在Java中重写方法:

class Animal {public void sound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {@Override // 这是一个注解,用于指示该方法重写了父类的方法public void sound() {System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Animal myAnimal = new Dog(); // 向上转型myAnimal.sound(); // 输出 "Dog barks",展示了运行时多态}
}

在这个例子中,Dog 类继承自 Animal 类,并重写了 sound() 方法。当我们创建 Dog 类的实例并将其向上转型为 Animal 类型时,调用 sound() 方法会执行 Dog 类中重写的方法,而不是 Animal 类中的原始方法。这就是多态性的一个典型应用,它允许程序在运行时根据对象的实际类型来确定调用哪个方法。

了解完重写我们在看看,下面的代码:

public class Animal {String name="aaaa";public void eat(){System.out.println("吃东西。。。。。");}
}class Dog extends Animal{String name;public Dog(String name) {this.name = name;}public void eat(){System.out.println("吃狗粮。。。");}}class Cat extends Animal{String name;public Cat(String name) {this.name = name;}public void eat(){System.out.println("吃猫粮。。。");}}class Test{public static void main(String[] args) {Animal animal=new Dog("旺财");animal.eat();animal=new Cat("小黑");animal.eat();}}

image.png
我们在调用eat()方法时却呈现了不同的形态,即:一个吃猫粮,一个吃狗粮。

我们也可以用静态方法实现多态如下:

public class Animal {String name="aaaa";public void eat(){System.out.println("吃东西。。。。。");}
}class Dog extends Animal{String name;public Dog(String name) {this.name = name;}public void eat(){System.out.println("吃狗粮。。。");}}class Cat extends Animal{String name;public Cat(String name) {this.name = name;}public void eat(){System.out.println("吃猫粮。。。");}}class Test{
public static void eat(Animal animal){animal.eat();}public static void main(String[] args) {Dog dog=new Dog("旺财");eat(dog);Cat cat=new Cat("小黑");eat(cat);}}

image.png
这里我们在Test中实现了一个静态方法eat(Animal animal)然后传递一个对象进去即可完成多态。
其实上面的代码还涉及了,类的向上转型。我们接下来就讲讲向上转型和向下转型。

向上转型和向下转型

在Java中,向上转型(Upcasting)和向下转型(Downcasting)是面向对象编程中多态性的一部分,它们允许我们处理不同类型的对象,但以更通用的类型进行操作。
向上转型(Upcasting)
向上转型是指将子类对象赋值给父类引用的过程。向上转型是安全的,因为子类是父类的特化。这意味着子类继承了父类的所有属性和方法,所以子类对象可以被看作是父类对象。
示例代码:

class Animal {void makeSound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {void makeSound() {System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Animal myAnimal = new Dog(); // 向上转型myAnimal.makeSound(); // 将调用Dog类的makeSound方法}
}

在这个例子中,Dog 类是 Animal 类的子类。我们创建了一个 Dog 类的实例,并将这个实例赋值给 Animal 类型的引用 myAnimal。由于向上转型是安全的,编译器允许这样做,并且当我们调用 makeSound() 方法时,将调用 Dog 类中重写的方法。
向下转型(Downcasting)
向下转型是指将父类对象赋值给子类引用的过程。向下转型是不安全的,因为父类引用可能没有指向实际的子类对象。如果向下转型不正确,将会导致 ClassCastException。
示例代码:

class Animal {void makeSound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {void makeSound() {System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Animal myAnimal = new Dog();Dog myDog = (Dog) myAnimal; // 向下转型if (myAnimal instanceof Dog) {Dog myDogSafe = (Dog) myAnimal; // 安全的向下转型myDogSafe.makeSound(); // 将调用Dog类的makeSound方法} else {System.out.println("myAnimal is not a Dog");}}
}

在这个例子中,我们首先向上转型,将 Dog 对象赋值给 Animal 类型的引用 myAnimal。然后我们尝试向下转型,将 myAnimal 转换为 Dog 类型的引用 myDog。如果 myAnimal 实际上指向了一个 Dog 对象,那么向下转型将成功,否则将抛出 ClassCastException。
为了安全地进行向下转型,可以使用 instanceof 操作符来检查 myAnimal 是否确实指向了一个 Dog 对象。如果 instanceof 检查为 true,那么向下转型是安全的。

注意:
向上转型后只能调用父类的成员和方法,无法再调用子类特有的成员变量或方法。


一个小坑

避免在调用构造方法时调用已经重写过的方法,否则很容易出错。
如下代码:在实例化子类对象时,我们必须先调用完成父类的构造方法,然而Animal的构造方法又调用了子类的已经重写的方法func,这时发生动态绑定,方法执行重写的func,而此时num的值未完成初始化,就打印了0出来,所以打印结果就如下图:

public class Test {public static void main(String[] args) {Dog dog=new Dog();}
}class Animal{public void func(){System.out.println("动物");
}public Animal(){func();
}}class Dog extends Animal{int num=999;public void func(){System.out.println("狗");System.out.println(num);}}

image.png

浅谈final关键字

第一:final修饰类,则类不能被继承
image.png

第二:修饰类的方法则方法不能被重写
image.png

第三:修饰成员变量则变量相当于常量,无法在进行修改。
image.png

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

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

相关文章

######## mysql各章节终篇索引 ########

关系图: 事务特性 原子性 持久性 隔离性 隔离级别(RC、RR等4个) 锁 mvcc 一致性 1、索引 【聚集(聚簇)/非聚集(非聚簇)/二级索引、覆盖索引、主键自增的影响】#### 聚集(聚簇)、非聚集(非聚簇)、二级索引,覆盖索引,及…

低代码开发平台一般都有哪些功能和模块?

在当今快速变化的数字化时代,企业对于高效、灵活且经济的软件开发解决方案的需求愈发迫切。低代码开发平台应运而生,成为众多企业实现数字化转型的首选工具。本文将详细探讨低代码开发平台一般具备的主要功能和模块,以及它们如何助力企业提升…

6月5日 C++day3

#include <iostream>using namespace std;class Per { private:string name;int age;int *high;double *weight; public:Per(){cout << "Per的无参构造" << endl;}Per(string name,int age,int high,double weight):\name(name),age(age),high(new…

trace32 显示用户进程用户态调用栈

在只加载了linux vmlinux符号表的情况下&#xff0c;trace32 只能显示内核态的调用栈函数信息&#xff0c;无法显示用户态调用栈的函数信息&#xff1a; 查看进程maps 确认地址0x40616C为进程/bin/box的虚拟地址&#xff1b;而0xFFFF904E12FC为/lib/libc-2.30.so的地址&#x…

代码随想录算法训练营day44 | 01背包问题 二维、01背包问题 一维、416. 分割等和子集

01背包问题 二维 1. 确定dp数组以及下标的含义 dp[i][j] 表示从下标为[0-i]的物品里任意取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大是多少。 2. 确定递推公式 dp[i][j] max(dp[i - 1][j], dp[i - 1][j - weight[i]] value[i]) 3. dp数组如何初始化 首先从…

有多少苹果用来分赃

题目描述&#xff1a; 有5个人偷了一堆苹果&#xff0c;他们准备在第二天进行分赃。晚上&#xff0c;有一个溜出来&#xff0c;他把所有苹果分成了5份&#xff0c;但是多了一个&#xff0c;他顺手把多的一个苹果扔给树上的猴子&#xff0c;自己先拿1/5藏了起来。没想…

字节跳动Seed-TTS文本到语音模型家族

字节跳动的SEED TTS&#xff08;Seed-TTS&#xff09;是一系列大规模自回归文本转语音&#xff08;TTS&#xff09;模型&#xff0c;能够生成与人类语音几乎没有区别的高质量语音。该模型在语音上下文学习方面表现出色&#xff0c;尤其在说话者相似度和自然度方面的表现&#x…

Python 编程时可能会遇到各种错误提示

下是一些常见的 Python 错误提示及其简要解释&#xff1a; SyntaxError&#xff08;语法错误&#xff09; 示例&#xff1a;File "<stdin>", line 1, in <module> print("Hello, World! &#xff08;缺少闭合括号&#xff09;解释&#xff1a;Pyth…

篇1:Mapbox Style Specification

目录 引言 地图创建与样式加载 Spec Reference Root sources type:vector矢量瓦片

特惠电影票api接口文档,宜选影票接口文档不断优化

宜选影票接口文档的优化是一个持续的过程&#xff0c;旨在提高API的易用性、稳定性和安全性。以下是根据参考文章和相关经验&#xff0c;对宜选影票接口文档优化的一些建议&#xff0c;采用分点表示和归纳的方式&#xff1a; 1. 明确接口目标和功能 清晰定义&#xff1a;在接…

css动画案例练习之会展开的魔方和交错的小块

这里写目录标题 一级目录二级目录三级目录 下面开始案例的练习&#xff0c;建议第一个动手操作好了再进行下一个一、交错的小块效果展示1.大致思路1.基本结构2.实现动态移动 2.最终版代码 二、会展开的魔方1.大致思路1.基本结构;2.静态魔方的构建3.让静态的魔方动起来 2.最终版…

JavaScript第十讲:DOM编程(1):节点概念,如何获取元素节点,节点属性,样式练习题

前言 上一节是本文的知识点讲解&#xff0c;有需要的码客们先看一下&#xff0c;本文是练习题 题目要求 编写一个HTML文档&#xff0c;展示DOM编程的基础知识&#xff0c;包括节点概念的理解、如何获取元素节点、节点属性的操作以及样式调整。要求文档中包含一个带有特定ID的…

【MySQL】表的基本操作

&#x1f30e;表的基本操作 文章目录&#xff1a; 表的基本操作 创建查看表       创建表       查看表结构 表的修改       表的重命名       表的添加与修改       删除表结构 总结 前言&#xff1a; 在数据库中&#xff0c;数据表是存储和组…

vue脚手架 笔记01

01 页面组件 所谓的组件就是把页面每一块内容单独分离出去封装起来 组件包括自己本身的html css 和 js 可以被反复引入使用 (复用) 方便后期维护(方便快速的增加或者删除指定页面的指定模块) 组件化开发: 组件是独立的可复用的代码组织单元 组件系统是vue核心特性之一 组件分类…

鸿蒙状态管理-@Builder自定义构建函数

Builder 将重复使用的UI元素抽象成一个方法 在build方法里调用 使其成为 自定义构建函数 Entry Component struct BuilderCase {build() {Column(){Row(){Text("西游记").fontSize(20)}.justifyContent(FlexAlign.Center).backgroundColor("#f3f4f5").hei…

vue课后习题及答案

第一章 初识vue.js 一.填空题 1.Vue是一套用于构建___用户界面_____的渐进式框架. 2.Vue中的指令以______v-__开头. 3.Node.js 是一个基于____V8___引擎的JavaScript运行环境。 4.在yam 中&#xff0c;__yarn add__命令用于添加指定名称的包。 5.在 npm 中&#xff0c;___…

性能测试-测试方法总结(压力/负载)超详细

前言 并发/负载/压力理解 负载测试&#xff1a;通过不断加压使系统达到瓶颈&#xff0c;为调优提供参考数据 压力测试&#xff1a; 稳定性压力测试&#xff1a;在不同的给定的条件下&#xff08;比如内存的使用&#xff0c;一定时间段内有多少请求等&#xff09;&#xff0c…

IEAD常用快捷键

如题 网页图片不清晰&#xff0c;可下载后查看

【SHUD】PIHMgis编译过程(下)sundials及PIHM编译过程

文章目录 说明sundials编译sundialssundials源代码下载MINGW下sundials编译过程CMAKE下sundials编译过程(推荐)PIHM编译过程安装QT 5导入项目配置VSVS使用静态库文件qt deployment toolgdal.dll编译PIHMgis成功编译

代码随想录算法训练营Day60 | 84.柱状图中最大的矩形

代码随想录算法训练营Day60 | 84.柱状图中最大的矩形 LeetCode 84.柱状图中最大的矩形 题目链接&#xff1a;LeetCode 84.柱状图中最大的矩形 class Solution { public:int largestRectangleArea(vector<int>& heights) {int result 0;stack<int> st;height…