news 2026/10/31 11:07:06

instanceof 还能拆字段?Java 21 记录模式把对象一行拆平

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
instanceof 还能拆字段?Java 21 记录模式把对象一行拆平

instanceof 还能拆字段?Java 21 记录模式把对象一行拆平

系列:Java 后端实战精通营 · 作者:鱼宵
配套课程仓库:https://gitee.com/j67mk2/java21-journey (第 6 课)

先看一段"两层嵌套就看不下去"的代码

假设有个几何系统:圆(Circle)里套着圆心(Point),矩形(Rectangle)左上角也是个点。你要按形状打印描述,老写法是这样的:

if(sinstanceofCircle){Circlec=(Circle)s;// 第一层强转Pointp=c.center();// 取圆心doublex=p.x();// 再取坐标doubley=p.y();// 第三层了……}

两层嵌套就要两层强转 + 链式访问。等业务变成"订单套地址、地址套城市",这段代码谁看谁头大——强转链越长,越容易转错类型。

Java 21 的记录模式(Record Pattern)就是干这个的:类型判断、自动转型、拆字段三合一,一行拆到最内层。

一句话结论:记录模式 = 匹配类型的同时把 record 组件"拆"出来

记录模式(Record Pattern,JEP 440,JDK 21 正式特性):在instanceof/case后面写类型(组件类型 变量, ...),匹配成功就自动转型 + 把 record 的各个组件绑定给新变量。

类比:快递站拆包裹。老写法是先验货(instanceof 判断)、签收盖章(强转)、再一件件掏出来点数(手动调x()、y());记录模式是快递员一边验货一边把东西摊在你桌上——Point(int x, int y)就是"如果是 Point 包裹,把里面 x、y 两件货直接递给我"。

关键代码:老写法 vs 记录模式(完整可运行)

先看"检查依据"——密封图形家族(第 4 课 sealed + 第 5 课 switch 的知识点,本课合体):

/** 密封家族:Circle、Rectangle 两个成员,switch 才敢不写 default */publicsealedinterfaceShapepermitsCircle,Rectangle{}recordPoint(intx,inty){}// 点recordCircle(Pointcenter,doubler)implementsShape{}// 圆:嵌套了 PointrecordRectangle(PointtopLeft,doublew,doubleh)implementsShape{}// 矩形:也嵌套了 Point

① instanceof 记录模式——三行变一行:

// 老写法:判断 + 强转 + 取字段,三步if(pointObjinstanceofPointp){intx=p.x();inty=p.y();// ... 用 x、y}// 新写法:一个动作全做完if(pointObjinstanceofPoint(intx,inty)){// 直接就能用 x、y}
  • instanceof Point(int x, int y):一个动作完成三件事——判断是不是 Point、是就自动转型、再把两个组件分别绑给变量 x、y。
  • 不匹配时整个条件为 false,x、y 不会被绑定,后面的分支里根本不能用它们——编译器帮你保证安全,不会出现"用了没绑定的变量"。

② switch 嵌套解构——一行拆到最内层:

staticStringdescribe(Shapes){returnswitch(s){caseCircle(Point(intx,inty),doubler)->"圆心("+x+", "+y+"),半径 "+r;caseRectangle(Point(inttx,intty),doublew,doubleh)->"左上角("+tx+", "+ty+"),宽 "+w+",高 "+h;};}
  • Circle(Point(int x, int y), double r):嵌套解构。外层匹配 Circle;第一个组件是 Point,括号里继续拆出 x、y;第二个组件直接绑给 r。一行拆到最内层——老写法要((Circle) s).center().x()这种强转 + 链式访问,两层嵌套就要两层强转。
  • Shape 是 sealed 且两个分支全覆盖,不需要 default(第 5 课同款穷尽性检查)。
  • 顺便:拆出来的组件本身是个 record 就接着拆,这就是俄罗斯套娃——“开大圆、再开圆心那个小点”。

③ 算面积不想拆,用 var 接住:

staticdoublearea(Shapes){returnswitch(s){caseCircle(varcenter,doubler)->Math.PI*r*r;// 不关心圆心坐标,var 整个接住caseRectangle(vartopLeft,doublew,doubleh)->w*h;};}
  • var center:类型照判(是 Circle 就行),但不拆组件。拆不拆随你——想拆写Point(int x, int y),不想拆写var。嵌套层深(订单套地址套城市),不想拆的那层就var接住。

④ 泛型坑:Box<String>写不了,Box<?>可以:

recordBox<T>(Tcontent){}// 报错!Object cannot be safely cast to Box<String>// if (box instanceof Box<String>(String s)) { ... }// 正确写法:通配符让泛型"退一步"if(boxinstanceofBox<?>(Objectcontent)){System.out.println("箱子里装着:"+content);}
  • Box<String>不是可具体化类型(reifiable):泛型类型参数编译后就被**擦除(erasure)**了,运行时Box<String>和Box<Integer>是同一个类Box,JVM 根本没机会验证"里面装的是不是 String",编译器宁可报错也不让你写这种"看似安全实则无法验证"的代码。
  • Box<?>在运行时就是"一个 Box,内容不知道"——这个判断是真的能做的,所以能解构。

实测输出:新旧写法行为一致,嵌套解构生效

我本机(JDK 21.0.12.1)的真实输出:

========== 第 6 课:记录模式 ========== --- 1) instanceof 老写法 vs 记录模式新写法 --- 老写法拿到:point(3, 4) 新写法拿到:point(3, 4) textObj 不是 Point,解构没发生:我不是 Point --- 2) switch 嵌套解构:一行拆到最内层 --- 描述圆:圆心(0, 1),半径 2.5 描述矩形:左上角(2, 3),宽 4.0,高 5.0 圆面积:19.634954084936208 矩形面积:20.0 --- 3) 记录模式与泛型:Box<?> 可以,Box<String> 不行 --- 箱子里装着:一封信

输出怎么读:

  • 老写法拿到和新写法拿到输出完全一样——记录模式只是少写代码,行为没变,重构安全。
  • textObj 不是 Point那行:传进去的是字符串,解构条件为 false 走 else——不匹配就不解构。
  • 描述圆:圆心(0, 1),半径 2.5:嵌套解构Circle(Point(int x, int y), double r)生效,x=0、y=1 是从 Point 里拆出来的。
  • 矩形面积:20.0:4 × 5 = 20,var topLeft接住整个点、不解构,面积照常算。
  • 箱子里装着:一封信:Box<?>(Object content)解构成功。

挑战题(答案都在课程源码里)

  1. ⭐照猫画虎:给 Shape 家族加record Line(Point start, Point end) implements Shape(记得更新 permits),在 describe 里加一个嵌套解构分支。
  2. ⭐改守卫:给 describe 加一条 when——“半径 > 10 的圆叫大圆”,看守卫子句怎么和嵌套解构配合。
  3. ⭐⭐试报错:把Box<?>(Object content)改成Box<String>(String s)亲手编译一次,把报错原文记下来(Object cannot be safely cast to Box<String>)。
  4. ⭐⭐var 对照:把 area 里的var center改成Point center再编译——体会"写全类型 = 要拆,var = 不拆"的差别。
  5. ⭐⭐⭐挑战:给 Point 加第三个组件int z(三维点),不修改 describe 直接编译——观察嵌套解构的编译报错,体会"record 加字段,解构代码被编译器逼着同步改"。

面试回答模板

问:记录模式了解吗?举个例子。

  • 一句话结论:记录模式是 JDK 21 转正的特性,让 instanceof 和 switch 在类型匹配的同时把 record 的组件直接拆出来绑给变量。
  • 展开 1~2 句原理/例子:比如case Circle(Point(int x, int y), double r)一行就能拆到圆心坐标,老写法要强转再链式访问;sealed 家族下还能做穷尽性检查,不用写 default。
  • 收一句应用场景:实际项目里处理"树形结构的数据"很常见,比如订单里嵌地址、报文里嵌对象,用记录模式比层层强转干净得多,也不容易漏分支。

预判追问:“Box 为什么不行?”——“泛型实参编译后擦除,运行时无法验证类型,报Object cannot be safely cast,变通写Box<?>”;追问"解构会改对象吗?"——“不会,record 不可变,解构只读,绑出来的是快照”。

总结表:坑 → 原因 → 解法

坑原因解法
嵌套对象强转链看不下去判断 + 强转 + 取字段绞在一起记录模式嵌套解构一行拆平
Box<String>编译报错泛型擦除,运行时无法验证Box<?>+Object content
解构括号和组件数对不上record 组件变了解构没同步编译器直接报错,逼你同步改
以为解构能改对象误把解构当修改record 不可变,解构只读
switch 不写 default 报"不完整"输入不是 sealed 家族sealed 圈死家族,或补 default
describe(null)抛 NPEswitch 对 null 求值显式加case null ->

关于这个系列

本文属于Java 后端实战精通营系列(Java 21 实战 10 课)。完整代码在java21-journey 课程第 6 课(lesson-06/src/main/java/com/java21/lesson06/,含Shape.java图形家族 +Main.java三组演示):

gitclone https://gitee.com/j67mk2/java21-journey.gitcdjava21-journey/lesson-06 mvn-qcleaninstall-DskipTestsjava-cptarget/classes com.java21.lesson06.Main

(仓库地址是小写 j 的 j67mk2,复制别丢字母。跑完会看到新旧写法输出一致、嵌套解构拆到圆心、Box<?> 解构成功。)

下一篇预告:顺序集合——SequencedCollection让"拿最后一个元素"从list.get(size-1)变成getLast(),增删首尾元素也不再是土办法。

掏心窝一句:记录模式 + sealed + switch 是三兄弟,前两课学的在这里"合体"。面试官问"Java 21 新特性",你把这三件套串成一个故事(sealed 圈家族 → switch 按类型分派 → 记录模式拆字段),比零散背特性名高一个段位。跑出输出和我不一样?评论区一起查。


【发布信息】

  • 主标题:instanceof 还能拆字段?Java 21 记录模式把对象一行拆平
  • 备选标题 2:订单套地址、圆里套点:Java 21 记录模式嵌套解构一行拆到最内层
  • 备选标题 3:Java 21 记录模式:类型判断+转型+拆字段三合一,Box 却写不了
  • 标签建议:java / Java21 / record
  • 摘要建议:圆里套点、订单套地址,嵌套对象的老写法要强转 + 链式访问,两层就看不下去了。Java 21 记录模式让 instanceof 和 switch 在匹配类型的同时把 record 组件直接拆出来——一行拆到最内层,顺带讲清 Box 为什么写不了(泛型擦除)。附完整代码、实测输出与面试回答模板。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 10:55:57

08-JDK 21 虚拟线程正式发布:并发写法彻底变了

JDK 21 是继 17 之后的第三个新制度 LTS&#xff0c;也是"现代 Java 真正成熟"的里程碑。它把酝酿了四年的虚拟线程正式转正&#xff0c;配合分代 ZGC、分代 Shenandoah、密钥增强、序列集合&#xff08;SequencedCollection&#xff09;等&#xff0c;一口气补齐了并…

作者头像 李华
网站建设 2026/10/31 10:54:29

ContextMenuManager:10 分钟把 Windows 右键菜单理干净的完整指南

ContextMenuManager&#xff1a;10 分钟把 Windows 右键菜单理干净的完整指南 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager ContextMenuManager 是一款 C# Win…

作者头像 李华
网站建设 2026/10/31 10:51:49

Sealos 离线部署:断网机房里装好 K8s 集群的完整流程

Sealos 离线部署&#xff1a;断网机房里装好 K8s 集群的完整流程 【免费下载链接】Sealos 以应用为中心的智能云操作系统 项目地址: https://gitcode.com/labring/Sealos 机房里网线已经拔掉&#xff0c;服务器一台台摆好&#xff0c;你要在完全断网的情况下&#xff0c…

作者头像 李华
网站建设 2026/10/31 10:40:27

【预测模型-ELAMN预测】基于海鸥算法优化ELMAN神经网络实现数据回归预测

1 简介风能,作为一种重要,有潜力,无污染,可再生、可持续的能源,已经成为全球发电最为迅速的能源之一,越来越受到世界各国的青睐。近年来,为缓解能源短缺问题,改善环境,实现经济乃至人类的可持续发展,世界各国纷纷大力发展风能资源。然而,在实际操作中,风能固有的波动性和间歇性…

作者头像 李华