当前位置: 首页 > news >正文

Day13 | Java多态详解

在上一篇文章Day12 | Java继承详解中,我们讲了一下"继承"怎么让代码复用变得简单。

今天我们来看一下"多态"怎么让代码更具有灵活性和扩展性。

多态也是面向对象三大特性中的核心特性之一。

一、多态是什么

多态字面理解就是多种形态。在Java中,它允许我们使用父类类型的引用,来指向子类对象,并根据实际对象类型来调用方法。

还是来看我们经常使用的动物类的案例:

package com.lazy.snail.day13;/*** @ClassName Animal* @Description TODO* @Author lazysnail* @Date 2025/5/28 10:26* @Version 1.0*/
public class Animal {public void shout() {System.out.println("动物叫");}
}

父类Animal定义了一个shout方法。

package com.lazy.snail.day13;/*** @ClassName Dog* @Description TODO* @Author lazysnail* @Date 2025/5/28 10:26* @Version 1.0*/
public class Dog extends Animal {@Overridepublic void shout() {System.out.println("狗叫:汪汪汪");}
}package com.lazy.snail.day13;/*** @ClassName Cat* @Description TODO* @Author lazysnail* @Date 2025/5/28 10:27* @Version 1.0*/
public class Cat extends Animal {@Overridepublic void shout() {System.out.println("猫叫:喵喵");}
}

Cat类和Dog都通过extends关键字继承Animal类。

并且重写(@Override)了Animal中的shout方法。

package com.lazy.snail.day13;/*** @ClassName Day13Demo* @Description TODO* @Author lazysnail* @Date 2025/5/28 10:27* @Version 1.0*/
public class Day13Demo {public static void main(String[] args) {Animal a1 = new Dog();Animal a2 = new Cat();a1.shout();a2.shout();}
}

在测试Demo中,我们并没有使用Dog dog = new Dog();和Cat cat = new Cat();创建猫狗对象。

而是直接使用了父类Animal指向了创建的子类猫狗的对象。

当使用对象.方法时,调用了子类对象的方法。

方法调用看对象实际类型,而不是变量声明类型。

二、多态的前提条件

整理了一下多态的一些前提条件:

条件

说明

继承

必须有父类与子类关系

方法重写

子类必须重写父类的方法

父类引用指向子类对象

Animal a = new Dog();

根据上面的案例:

1、UML类图,Cat和Dog类均继承Animal

 

2、Cat和Dog类均重写了父类Animal中的shout方法

 

3、Demo中创建对象时,均使用父类Animal指向子类对象

 

三、核心原理与引用类型转换

1、编译看左边,运行看右边

Animal a = new Dog(); 
a.shout();

编译阶段只看左边(Animal):只要Animal有shout方法,编译就通过;

运行阶段看右边(Dog):实际调用的是Dog的shout方法。

方法调用是动态绑定:运行时决定

如果把Animal中的shout方法注释(IDEA多行注释:选中代码块,Ctrl + Shift + /)

 

Demo中就会出现编译错误:

 

明确的指出了编译阶段,没办法在Animal中找到shout方法。

如果把Dog类中的shout方法注释(记得把Animal中shout方法的注释取消)。

 

再运行Demo,会看到dog对象调用shout方法后输出的是“动物叫”。

2、向上转型

Animal a = new Dog(); // 自动进行,不需要强转

安全、常见,是多态的基础。

但只能调用父类声明过的方法(即使子类重写了也可调用)

3、向下转型

Animal a = new Dog(); 
Dog d = (Dog) a; // 强制类型转换 d.shout();

有风险,可能ClassCastException,最好使用instanceof判断:

if (a instanceof Dog) {Dog d = (Dog) a;d.shout();
}

小结一下:

操作

方向

安全性

用途

向上转型

子 → 父

安全、自动

支持多态统一编程

向下转型

父 → 子

有风险、需强转

使用子类特有方法或属性

四、多态的变量访问

多态下变量的访问是静态绑定的,也就是只看编译时的类型,不会动态派发。

class Animal {String name = "动物";
}class Dog extends Animal {String name = "狗";
}public class Demo {public static void main(String[] args) {Animal a = new Dog();System.out.println(a.name);}
}

父子类中都定义了name属性。

Animal a =newDog();满足多态的条件,a.name输出的是“动物”。

编译阶段的类型是Animal,绑定的就是Animal中的name属性(看左边的类型)。

五、虚方法调用机制

Java中除了static、private、final修饰的方法外,其它方法都被视为虚方法,即运行时动态绑定。

当你写:

Animal a = new Dog();
a.shout();

JVM实际会在运行时根据对象的类型,从它的虚方法表中查找对应实现,然后调用。

后续讲到JVM的时候,会继续讲

六、多态应用场景

1、接口与抽象类的统一编程

public void startAnimal(Animal a) {a.shout(); // 不关心具体类型,统一接口
}

方法可以接受任意Animal子类,如Dog、Cat、Tiger等等。

2、面试常见:方法调用顺序

class A {public void show() {System.out.println("A.show()");}
}
class B extends A {public void show() {System.out.println("B.show()");}
}
class C extends B {public void show() {System.out.println("C.show()");}
}public class Test {public static void main(String[] args) {A obj = new C();obj.show();}
}

看看这个案例,理一下,脑跑一下代码,main方法中的obj.show会输出什么?

结语

小结下一本文关于多态的知识点:

概念

要点

多态

同一父类引用,调用不同子类的方法实现

条件

继承 + 方法重写 + 向上转型

编译 vs 运行

编译看变量类型,运行看对象实际类型

动态绑定

运行时确定方法实现,提高灵活性

变量访问

静态绑定,编译期确定

多态实际就是屏蔽具体实现差异,统一对外接口。 在后续的代码实践中,我们会在使用多态的地方继续了解多态的魅力。

下一篇预告

Day14 | 抽象类和接口

如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!

本文首发于知乎专栏《Java 100天成长计划》


文章转载自:

http://5yU7sZQ1.smrkf.cn
http://44PjFJsC.smrkf.cn
http://vEPW9Cu8.smrkf.cn
http://FXjUakEw.smrkf.cn
http://mGDeIhD2.smrkf.cn
http://89yfKgKK.smrkf.cn
http://yfCiDjci.smrkf.cn
http://3qr0hcwG.smrkf.cn
http://HkeKAyfZ.smrkf.cn
http://XMyEVSRV.smrkf.cn
http://kECkQ5DF.smrkf.cn
http://3QQEgCuz.smrkf.cn
http://8N2Q7Y7b.smrkf.cn
http://KrSygNci.smrkf.cn
http://6jSDaf8e.smrkf.cn
http://EB4eCgMu.smrkf.cn
http://0DHZrB8o.smrkf.cn
http://W7CdEZxZ.smrkf.cn
http://2w5EjbmC.smrkf.cn
http://4RYJxcEb.smrkf.cn
http://aCzfuVE5.smrkf.cn
http://FMMRyNpZ.smrkf.cn
http://JPy9p7Vi.smrkf.cn
http://SKEhpyrN.smrkf.cn
http://rQqYtYMH.smrkf.cn
http://rFjNYvfU.smrkf.cn
http://76FuiY84.smrkf.cn
http://BVhbnTd5.smrkf.cn
http://oDXcwn3S.smrkf.cn
http://xIPyiiXo.smrkf.cn
http://www.dtcms.com/a/378801.html

相关文章:

  • hbuilderx配置微信小程序开发环境
  • opc ua c#订阅报错【记录】
  • Caffeine 本地缓存最佳实践与性能优化指南
  • MySQL 高级特性与性能优化:深入理解函数、视图、存储过程、触发器
  • Java常见排序算法实现
  • 生产环境禁用AI框架工具回调:安全风险与最佳实践
  • Git - Difftool
  • leetcode28( 汇总区间)
  • 直击3D内容创作痛点-火山引擎多媒体实验室首次主持SIGGRAPH Workshop,用前沿技术降低沉浸式内容生成门槛
  • 鸿蒙next kit 卡片引入在线|本地图片注意事项
  • 学习番外:Docker和K8S理解
  • Leetcode 刷题记录 21 —— 技巧
  • 卷积神经网络CNN-part5-NiN
  • 散斑深度相机原理
  • 中元的星问
  • 使用 NumPy 读取平面点集并分离列数据
  • uni-app + Vue3 开发展示 echarts 图表
  • uni-app 网络请求封装实战:打造高效、可维护的HTTP请求框架
  • AppTest邀请测试测试流程
  • C#地方门户网站 基于NET6.0、Admin.NET,uniapp,vue3,elementplus开源的地方门户网站项目
  • 苹果上架全流程详解,iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传与审核要点完整指南
  • PyTorch之张量创建与运算
  • Python爬虫实战:研究GUI 可视化界面,构建电商数据采集和分析系统
  • 对浏览器事件机制的理解
  • JavaWeb05
  • 浅聊一下ThreadLocal
  • 部署大模型的极简笔记
  • linux面试题记录
  • 深度解码OpenAI的2025野心:Codex重生与GPT-5 APIKey获取调用示例
  • 文献阅读笔记:脉冲神经网络最新文献合集-IV