常见的多态

一、核心概念

多态(Polymorphism) 的字面意思是“多种形态”。在Java中,它指的是:同一个行为(方法)具有多个不同表现形式或形态的能力

更具体地说,它允许你:

  • 父类的引用指向子类的对象(向上转型)

  • 通过这个父类引用调用方法时,实际执行的是子类重写的方法

简单比喻:
打印机 是一个父类,它有 打印() 方法。黑白打印机 和 彩色打印机 是子类,它们都重写了 打印() 方法。当你用 打印机 my打印机 = new 彩色打印机(); 然后调用 my打印机.打印(); 时,打印出来的是彩色的。这就是多态——你下达的“打印”指令相同,但不同对象表现出不同的行为。


二、多态的实现的三要素(必要条件)

面试官常问:“实现多态需要什么条件?” 记住这三个必要条件:

  1. 继承关系:必须存在父子类关系。

  2. 方法重写(Override):子类必须重写父类的方法。

  3. 向上转型(Upcasting):父类的引用必须指向子类的对象。Parent p = new Child();


三、代码示例:一看就懂

// 1. 继承关系
class Animal {public void makeSound() {System.out.println("动物发出声音");}
}class Cat extends Animal {// 2. 方法重写@Overridepublic void makeSound() {System.out.println("喵喵喵");}// 猫特有的方法public void climbTree() {System.out.println("猫爬树");}
}class Dog extends Animal {// 2. 方法重写@Overridepublic void makeSound() {System.out.println("汪汪汪");}
}public class PolymorphismTest {public static void main(String[] args) {// 3. 向上转型:父类引用指向子类对象Animal myAnimal1 = new Cat(); // 编译时类型是Animal,运行时类型是CatAnimal myAnimal2 = new Dog(); // 编译时类型是Animal,运行时类型是Dog// 多态的体现:同一个方法调用,表现出不同行为myAnimal1.makeSound(); // 输出: 喵喵喵myAnimal2.makeSound(); // 输出: 汪汪汪// myAnimal1.climbTree(); // 这行代码会编译报错!// 因为编译看左边,编译器认为myAnimal1是Animal类型,而Animal类没有climbTree方法。// 如果想要调用子类特有方法,需要向下转型if (myAnimal1 instanceof Cat) {Cat myCat = (Cat) myAnimal1; // 向下转型myCat.climbTree(); // 输出: 猫爬树}}
}

四、深入原理:编译时 vs. 运行时

这是理解多态底层机制的关键,面试必问。

  • 编译时(Compile-time)

    • 编译器只认引用类型(声明的类型)

    • 它检查你调用的方法在父类中是否存在,以及参数、访问权限等是否正确。这就是 “编译看左边”

    • 如果父类中没有该方法,直接编译失败。

  • 运行时(Run-time)

    • JVM认的是实际对象的类型(new出来的类型)

    • 它根据对象在堆中的实际类型,来决定调用哪个重写的方法。这就是 “运行看右边”

    • 这个动态绑定的过程是通过方法表(Method Table) 和虚方法调用(Virtual Method Invocation) 实现的。

底层机制:
JVM为每个类维护一个方法表。当通过父类引用调用方法时,JVM会找到实际对象的方法表,并从其中找到要执行的方法地址。这就是为什么它能准确调用子类方法的原因。


五、经典面试题与解答

1. 多态的作用和好处是什么?

答:

  1. 提高代码的可扩展性和可维护性:这是最重要的好处。代码不必为每个新子类做大量修改。例如,新增一个 Bird 类,animal.makeSound() 的代码完全不用动。

  2. 消除类型之间的耦合关系:调用者只需要面向父类编程,无需关心具体的子类实现。

  3. 接口性:方法接收父类参数,可以传入任意子类对象,使得设计更通用。

2. 多态中成员访问的特点?(超级高频!)

答:

  • 成员变量编译和运行都看左边(父类)

    • 访问的是父类中定义的成员变量,而不是子类的。

  • 成员方法编译看左边(父类),运行看右边(子类)

    • 编译时检查父类是否有该方法,运行时执行子类重写的方法。

  • 静态方法编译和运行都看左边(父类)

    • 静态方法与类绑定,不属于对象,因此不存在重写(Override)的概念,只有隐藏(Hide)。没有多态性

代码验证:

class Fu {int num = 10;public void show() { System.out.println("Fu show"); }public static void staticShow() { System.out.println("Fu static show"); }
}
class Zi extends Fu {int num = 20;@Overridepublic void show() { System.out.println("Zi show"); }public static void staticShow() { System.out.println("Zi static show"); }
}public class Test {public static void main(String[] args) {Fu fu = new Zi();System.out.println(fu.num); // 输出: 10 (成员变量看父类)fu.show(); // 输出: Zi show (成员方法看子类)fu.staticShow(); // 输出: Fu static show (静态方法看父类)}
}
3. 重写(Override)和重载(Overload)的区别?
特性重写 (Override)重载 (Overload)
发生范围父子类之间同一个类内部
方法名必须相同必须相同
参数列表必须完全相同必须不同(类型、个数、顺序)
返回值相同或是其子类(协变返回类型)可以不同
访问权限不能比父类更严格可以不同
异常不能抛出比父类更宽泛的检查型异常可以不同
核心运行期多态的实现编译期多态的实现
4. 向下转型时需要注意什么?

答: 需要使用 instanceof 关键字进行类型检查,避免抛出 ClassCastException

Animal animal = new Cat();
if (animal instanceof Dog) { // 这里会返回falseDog dog = (Dog) animal; // 不会执行到这行,避免了错误
}
5. 构造方法能否被重写?私有方法能否被重写?

答:

  • 构造方法不能被重写。因为构造方法名必须与类名相同,父子类类名不同。

  • 私有方法(private)不能被重写。私有方法在子类中不可见,子类中写一个同名方法只是一个新的方法,与父类无关。

6. 多态的应用场景有哪些?

答:

  1. 数据库连接Connection conn = DriverManager.getConnection(url); 返回的实际是某个数据库厂商驱动的连接对象。

  2. Spring框架的IoC/DI@Autowired 注入接口,实际运行时注入的是其实现类的对象。这是多态最经典的应用。

  3. 集合框架List<String> list = new ArrayList<>();,面向接口编程,方便后续更换实现(如换成 LinkedList)。


总结与面试回答技巧

当被问到“谈谈你对多态的理解”时,你可以按这个结构回答:

  1. 下定义:多态是面向对象三大特性之一,指同一行为的不同表现形态。

  2. 讲条件:实现多态需要继承、方法重写和向上转型三个条件。

  3. 说原理:其核心机制是“编译看左边,运行看右边”,JVM通过方法表进行动态绑定。

  4. 谈区别:区分成员变量、成员方法、静态方法在多态中的不同表现。

  5. 举例子:结合数据库连接、Spring注入等实际开发中的例子说明其巨大好处(解耦、扩展性强)。

  6. 挖深度:如果可以,可以提一下方法分派(Method Dispatch)等稍深的概念,展示你的深度。

这样的回答既有广度又有深度,能够充分展现你的Java功底。

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

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

相关文章

20250909_排查10.1.1.190档案库房综合管理系统20250908备份缺失问题+优化scp脚本(把失败原因记录进日志)并测试脚本执行情况

目录 一、现象(图中现象) 二、可能原因 1、本地源文件没生成(最可能原因) 2、清理逻辑误删 三、时间同步检查 1、运行命令查看当前时间源:w32tm /query /source 2、修改为内网 NTP 服务器 10.1.10.251: 四、脚本优化 1、scp.bat vs roboscp.bat 对比表 2、robo…

OpenHarmony之有源NFC-connected_nfc_tag模块详解

1. 模块概述 Connected NFC Tag模块是OpenHarmony NFC子系统的一部分,专门用于处理有源NFC标签的读写操作。与基础NFC模块不同,该模块专注于与已连接的有源NFC标签进行交互,提供更高层次的API供应用层使用。 设备必须具备有源NFC标签芯片,才能使用有源NFC标签的读和写服务…

MySql案例详解之事务

下面我会从“事务是什么”→“为什么需要事务”→“事务的四大特性&#xff08;ACID&#xff09;”→“MySQL中怎么用事务”→“常见坑与调试技巧”→“完整实战案例&#xff08;含代码、输出、讲解&#xff09;”六个层次&#xff0c;给你一个“看完就能上手”的MySQL事务速查…

Linux之环境变量(内容由浅入深,层层递进)

一、概念介绍&#xff08;来源&#xff1a;比特就业课&#xff09;环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数环境变量通常具有某些特殊用途&#xff0c;并且在系统中通常具有全局特性二、现象引入与解答 1.为什么像ls这样的系统指令可以直接执行&#x…

监控 Linux 服务器资源

使用 Bash 脚本监控 Linux 服务器资源并发送告警邮件前言一、&#x1f6e0;️ 脚本功能概览二、 &#x1f4dc; 脚本核心逻辑分解2.1. 变量初始化2.2. CPU 使用率监控2.3. 内存使用率监控2.4. 磁盘使用率监控2.5. 磁盘 IO 延迟监控&#xff08;await&#xff09;2.6. 网络流量监…

随机获取数组内任意元素

Math.random() * arr.length 是 JavaScript 中常用的表达式&#xff0c;用于生成一个范围在 [0, arr.length) 之间的随机浮点数&#xff08;包含 0&#xff0c;但不包含数组长度本身&#xff09;。 作用说明&#xff1a; Math.random() 生成一个 [0, 1) 区间的随机浮点数&#…

android studio gradle 访问不了

1.通过国内镜像站 2.通过本地部署 参考这个搞定 https://blog.csdn.net/2401_82819685/article/details/144542784

科普:企业微信的第三方应用涉及的“配置应用权限”

企业微信的第三方应用涉及“配置应用权限”&#xff0c;它在不同阶段含义不同&#xff1a;开发阶段意指应用自身所需的功能权限&#xff0c;安装阶段意指企业管理员对应用使用范围的控制&#xff0c;产生此歧义的问题&#xff0c;归根到低还是语言的缩写问题&#xff0c;设想一…

YOLOv11改进大全:从卷积层到检测头,全方位提升目标检测性能

## 1 引言YOLO&#xff08;You Only Look Once&#xff09;系列作为目标检测领域的重要算法&#xff0c;以其**高效推理**和**良好精度**赢得了广泛认可。2024年9月&#xff0c;Ultralytics团队正式发布了YOLOv11&#xff0c;在先前版本基础上引入了**多项架构改进**和**训练优…

JWT全面理解

目录 一、JWT是什么 1、身份认证&#xff08;最核心用途&#xff09; 2、信息交换 3、授权控制 二、JWT的核心价值 三、如何理解JWT的结构和工作原理 1、三部分结构解析 2、核心工作流程 四、JWT的使用步骤 1、添加依赖 2、添加配置文件 3、创建实体类 4、创建JWT…

量子文件传输系统:简单高效的文件分享解决方案

&#x1f310; 在线体验地址&#xff1a;https://share-file.narutogis.com/ &#x1f4e4; 项目概述 量子文件传输系统是一款基于Python Flask开发的高效文件管理与分享工具&#xff0c;致力于提供简单、安全、可靠的文件传输解决方案。系统支持用户管理、文件上传下载、自动…

基于 GitHub Actions 的零成本自动化部署:把 Vite/Vue3 项目一键发布到 GitHub Pages 的完整实战

1. 实现自动化部署1.1. 创建 vue 项目# 1. 安装/确认 Node.js&#xff08;>14&#xff09; node -v # 推荐 20.x# 2. 创建项目&#xff08;交互式&#xff0c;选 Vue3 Router 等&#xff09; npm init vuelatest github-actions-demo # 创建vite项目 # 或&#xff1a;v…

minio 文件批量下载

MinIO 批量下载功能说明 1. 功能描述 前端勾选多个对象文件后&#xff0c;一次性将这些对象从 MinIO 拉取并打包成 ZIP&#xff0c;通过浏览器直接下载。整体特性&#xff1a; 支持跨桶批量下载&#xff08;不同 bucket 的对象可同时下载&#xff09;。服务端采用流式压缩边…

机器学习11——特征选择与稀疏学习

上一章&#xff1a;机器学习10——降维与度量学习 下一章&#xff1a;【从 0 到 1 落地】机器学习实操项目目录&#xff1a;覆盖入门到进阶&#xff0c;大学生就业 / 竞赛必备[TOC] 机器学习实战项目&#xff1a;【从 0 到 1 落地】机器学习实操项目目录&#xff1a;覆盖入门到…

整理python快速构建数据可视化前端的Dash库

一.Dash框架# 导入 Dash 相关库 import dash from dash import dcc, html # dcc 是 Dash 核心组件库&#xff0c;html 是 HTML 组件库 from typing import Generic# 创建一个 Dash 应用实例 app dash.Dash(__name__)# 定义应用的布局 app.layout html.Div(children[# 添加一…

RNN循环神经网络(一):基础RNN结构、双向RNN

RNN循环神经网络 什么是循环神经网络&#xff1f; 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类专门用于处理序列数据的神经网络架构。与传统的前馈神经网络不同&#xff0c;RNN具有"记忆"能力&#xff0c;能够捕捉数据中的时间依赖关系…

#C语言——刷题攻略:牛客编程入门训练(十):攻克 循环控制(二),轻松拿捏!

&#x1f31f;菜鸟主页&#xff1a;晨非辰的主页 &#x1f440;学习专栏&#xff1a;《C语言刷题合集》 &#x1f4aa;学习阶段&#xff1a;C语言方向初学者 ⏳名言欣赏&#xff1a;"代码行数决定你的下限&#xff0c;算法思维决定你的上限。" 目录 1. BC82 乘法表…

daily notes[16]

文章目录意大利语单词 **“bello”**一、核心含义二、变形规则&#xff1a;最重要的部分1. 当 “bello” 位于 **名词前面** 时2. 当 “bello” 位于 **名词后面** 或 **动词后面** 时三、用法总结与对比四、其他用法和常见表达references意大利语单词 “bello” 融合了 指示形…

【知识库】计算机二级python操作题(二)

文章目录基本操作题1基本操作题2基本操作题3简单应用题1简单应用题2综合应用题1基本操作题1考生文件夹下存在一个文件PY101.py&#xff0c;请写代码替换横线&#xff0c;不修改其他代码&#xff0c;实现以下功能&#xff0c;随机选择一个手机品牌屏幕输出。 # 请在...处使用一行…