Java的多态:使用内存图理解运行时多态

ops/2025/2/11 9:34:13/

一、什么是多态

多态指多种形态,多态允许同一个方法在不同对象中表现出不同的行为。换句话说,在多态的情况下,相同的接口可以指向不同的实现

父类的引用指向子类的对象,子类的对象也可以向上转型到父类的类型接收,即一个类的句柄可以指向自己类的对象或者是自己子孙后代类的对象,从而实现不同子类对象的特殊化操作或统一操作

例如,小明在保定找到一家驴肉火烧,这家驴肉火烧店有意思,用长火烧做驴肉火烧,用圆火烧做夹土豆丝。长火烧和圆火烧都是火烧,一个用来夹驴肉,一种用来夹土豆丝。这就是多态,即同一事件(如夹东西),在不同的事物(长火烧和圆火烧)上就会产生不同的结果(驴肉火烧和夹土豆丝)。

 二、Java变量的数据类型指定

要彻底理解Java类与继承类在内存中的表现形式,就要理解Java中不同数据类型的内存存储差异。在 Java 中,数据类型分为基本数据类型引用数据类型,它们在内存中的存储形式是不同的。

基本数据类型是 Java 中最基础的数据类型,它直接存储数据的值。常见的基本数据类型包括:byteshortintlongfloatdoublechar 和 boolean。每种基本数据类型占用的内存大小是固定的,并且它们在内存中的存储方式是直接存储值。

以 intbyte 和 float 为例,它们在内存中的存储形式如下:

int 类型:占用 32 位(4 字节),其中 1 位是符号位,31 位是数值位。例如,int a = 10; 在内存中的二进制表示为:

00000000 00000000 00000000 00001010

 byte 类型:占用 8 位(1 字节),1 位符号位,7 位数值位。例如,byte a = 10; 在内存中的二进制表示为:

00001010

  float 类型:占用 32 位(4 字节),包含 1 位符号位、8 位指数位和 23 位尾数位。例如,float a = 10.0f; 在内存中的二进制表示为:

 0 10000001 01000000000000000000000

 由上面的基本数据类型的例子可以得到:不同的数据类型在内存中的存储形式是不一样的,即Java 的数据类型决定了数据在内存当中的存储形式。

三、父类 Animal 和子类 Cat

java">class Animal{}public class Cat extends Animal{public static void main(String[] args){Animal cat = new Cat();}
}

对于上面类 Animal 和类 Cat 的继承关系,类 Animal 的句柄 cat 指向了一个 Cat 对象,懵啦,这Animal 约束的句柄怎么能指向一个非Animal类的对象呢?好,那么带着这个疑问继续往下看。

根据继承中,创建子类对象之前先创建父类对象的规则,当我们 new Cat() 后,内存中有一块既有类Animal 的方法和变量又有类 Cat 的方法和变量的空间,如下图(省略方法区,只针对堆区和栈区)。

main方法入栈,cat变量指向一个Cat对象,但是cat是Animal类型,父类类型修饰的子类对象只能调用父类中未被子类重写的方法,以及子类中重写的方法。咱们举个例子简单说。

java">class Animal{public void Eat(){System.out.println("Animal的吃");}public void Eat(String name){System.out.println(name+"在吃");}
}public class Cat extends Animal{public void Eat(){System.out.println("Cat的吃");}public static void main(String[] args){Animal cat = new Cat();cat.Eat(); // 输出:Cat的吃}
}

现在Animal类中有两个Eat方法,一个有参一个无参,Cat类中有一个无参的Eat方法,那么Animal类中无参的Eat方法就被Cat类中无参的Eat方法重写,所以cat调用Eat()方法时,会输出

Cat的吃

 文字比较绕口的话,可以看看下图

 如果在main方法中再添加一行代码:

java">Cat cat_all = new Cat();

那么cat_all 可以调用Animal类中的方法,以及Cat类中的方法。

四、ABCD四个类理解向上转型

1、什么是向上转型

多态可以解决Java语言设计当中的问题——数据的向上转型,即数据类型的转换。

多态使用向上转型来解决数据类型的转换,即子类的对象可以由父类的类型接收,以扩充当前对象的能力,让一个行为表现出不同的形态和形式

2、直接上类

看代码

java">class A {public String Show(D obj) {return "A and D";}public String Show(A obj) {return "A and A";}public String Show() {return "无参的A";}
}
class B extends A{public String Show(Object obj) {return "B and B";}public String Show(A obj) {return "B and A";}public String Show() {return "无参的B";}
}
class C extends B{}
class D extends B{}
public class Test {public static void main(String[] args) {A a1 = new A();A a2 = new B();B b1 = new B();C c = new C();D d = new D();System.out.println(a1.Show());System.out.println(a2.Show());System.out.println(b1.Show());System.out.println(a1.Show(b1));System.out.println(a1.Show(c));// 不用向上转型System.out.println(a1.Show(d));System.out.println(a2.Show(b1));System.out.println(a2.Show(c));System.out.println(a2.Show(d));System.out.println(b1.Show(b1));System.out.println(b1.Show(c));System.out.println(b1.Show(d));}
}

ABCD满天飞的,看懵了吧,咱用内存图一点点分析每句System.out.println

1. System.out.println(a1.Show());

A a1 = new A();

System.out.println(a1.Show());

这句非常简单,A类对象调用自己类里的无参Show方法,输出“无参的A”。无关继承和多态。

2. System.out.println(a2.Show());

A a2 = new B();

System.out.println(a2.Show());

A类接收子类B的对象,那么a2只能使用A类中方法,B类又重写A类中无参Show方法和参数为A类型的Show方法,那么此句输出“无参的B”

3. System.out.println(a1.Show(b1));

A a1 = new A();

System.out.println(a1.Show(b1));

 咱们发现了,所有方法中没有参数为B类型的方法啊。此时就涉及到向上转型。B类继承了A类,Java会默认将b1向上转型,b1所指向的内存空间中有A类的内容,可以完成转型。那么此句输出“A and A”

完整的输出内容如下

无参的A
无参的B
无参的B
A and A
A and A
A and D
B and A
B and A
A and D
B and A
B and A
A and D

五、总结多态的实现条件

1、继承:子类必须继承父类才能实现多态;

2、方法重写:子类必须重新父类的方法;

3、父类引用指向子类对象。


http://www.ppmy.cn/ops/157489.html

相关文章

MySQL实战宝典:从调优到高可用架构设计全解析

MySQL作为全球最流行的开源关系数据库,支撑着互联网70%以上的在线业务。本文将揭秘淘宝双11每秒百万级TPS背后的数据库设计哲学,手把手带您构建高性能、高可靠的MySQL体系。 🚀 一、MySQL架构核心揭秘 存储引擎双雄对决: sql 复…

openGauss 3.0 数据库在线实训课程6:学习用户一次只能连接到一个数据库,没法访问其他数据库的对象

前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见:openGauss 3.0.0数据库在线实训课程 学习目标 学习openGauss体系结构,通过实验,了解用户一次只能连接到一个数据库,没法访问其他数据库的对象。 课程作…

北京青蓝智慧科技: 2025年ITSS IT服务项目经理的转型与挑战

2025年,随着信息技术的持续快速发展,IT服务管理(ITSS)在企业运营中的关键作用将进一步凸显。作为一位资深IT行业分析师,我预测2025年的IT服务经理将面临诸多挑战,同时也将迎来新的发展机遇。 人工智能&…

Redis03 - 高可用

Redis高可用 文章目录 Redis高可用一:主从复制 & 读写分离1:主从复制的作用2:主从复制原理2.1:全量复制2.2:增量复制(环形缓冲区) 3:主从复制实际演示3.1:基本流程准…

TRL - Transformer Reinforcement Learning(基于Transformer的强化学习)

TRL - Transformer Reinforcement Learning(基于Transformer的强化学习) flyfish 地址:https://github.com/huggingface/trl TRL是一个用于对基础模型进行后训练的全面库,是一个前沿的库,专门用于使用先进的技术&am…

使用deepseek快速创作ppt

目录 1.在DeekSeek生成PPT脚本2.打开Kimi3.最终效果 DeepSeek作为目前最强大模型,其推理能力炸裂,但是DeepSeek官方没有提供生成PPT功能,如果让DeepSeek做PPT呢? 有个途径:在DeepSeek让其深度思考做出PPT脚本&#xf…

【DeepSeek】Deepseek辅组编程-通过卫星轨道计算终端距离、相对速度和多普勒频移

引言 笔者在前面的文章中,介绍了基于卫星轨道参数如何计算终端和卫星的距离,相对速度和多普勒频移。 【一文读懂】卫星轨道的轨道参数(六根数)和位置速度矢量转换及其在终端距离、相对速度和多普勒频移计算中的应用 Matlab程序 …

【R】Dijkstra算法求最短路径

使用R语言实现Dijkstra算法求最短路径 求点2、3、4、5、6、7到点1的最短距离和路径 1.设置data,存放有向图信息 data中每个点所在的行序号为起始点序号,列为终点序号。 比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)…