面试官问:JDK 17/21核心新特性(虚拟线程/Record/密封类)?一张图+办公流程比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)

面试官问:JDK 17/21核心新特性(虚拟线程/Record/密封类)?一张图+办公流程比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)

预计阅读:14分钟

📌 你是不是也这样:还在用JDK 8,面试官一问“JDK 17和21有哪些新特性”就只知道“好像有个虚拟线程”,具体怎么回事完全讲不清楚?

今天一张图 + 一个办公流程故事 + 深度解析 + 五道追问,彻底拿下这道题。

📝摘要:JDK 17和21是Java最新的两个LTS版本,标志着Java从“企业级稳重”走向“现代化高效”。JDK 17带来Record类(告别POJO样板代码)、密封类(精准控制继承边界)、模式匹配(简化类型判断与解构);JDK 21带来虚拟线程(百万级并发,彻底改变高并发编程范式)、结构化并发(子任务生命周期自动管理)、顺序集合(统一有序集合操作)。一句话:JDK 17让代码更简洁安全,JDK 21让并发更轻量强大。


我是折哥,《Java 85题图解版》系列连载中(已更新41题,建议收藏本系列)。
每周2-3篇,85题通关路线一键追完。
👉点击关注,第一时间收到每篇新题推送。

  • 上一篇:面试官问:序列化与反序列化(含框架对比)?
  • 下一篇预告:面试官问:Java模块化(Project Jigsaw)与反射限制?(待发布)
  • 全部85题:点击查看总目录(关注专栏,追更不迷路

一句话总结:JDK 17让代码更简洁安全,JDK 21让并发更轻量强大。

Record类:一行代码定义不可变数据载体,自动生成构造器、equals、hashCode、toString → 像用标准化表格替代以前要填几页的复杂表单,一句话搞定所有字段。

密封类(Sealed Classes):通过sealedpermits精确控制哪些类可以继承 → 像公司明确指定只有某些部门可以接触核心文件,其他人碰都不能碰。

虚拟线程(Virtual Threads):JVM管理的轻量级线程,创建成本仅几百字节内存 → 像从“一人一车”升级到“共享单车”——几百万辆车成本极低,随用随走。

结构化并发(Structured Concurrency):子任务与父任务生命周期绑定 → 像团队有了组长统筹,一个子任务失败自动取消所有子任务,不会“各干各的”。

背诵口诀JDK 17 Record、密封、模式匹配;JDK 21 虚拟线程、结构化并发、顺序集合、作用域值。

核心设计理念JDK 17让代码更简洁安全,JDK 21让并发更轻量强大。

💬 面试还原

面试官:JDK 17和21分别引入了哪些核心新特性?你实际项目中用过哪些?

这是Java后端面试中区分“技术视野”的核心题,直接进入正题。

🧠 一图看懂:JDK 17/21核心新特性全景


🍵 生活比喻:从“写材料”到“开公司”

JDK 17 = 精简办公流程

  • Record类 = 标准化表格:以前填个表格要写一堆字段、构造器、getter(POJO),现在一张标准化表格(Record)一行搞定
  • 密封类 = 明确谁有权限:以前谁都能继承你的类(开放继承),现在明确指定只有某些人可以继承(密封类),像公司只允许指定部门接触核心文件
  • 模式匹配 = 智能识别:以前判断类型要两步(先instanceof再强转),现在一步到位,像安检系统一眼认出你是谁

JDK 21 = 从“卡车运输”到“共享单车”

  • 虚拟线程 = 共享单车:传统线程是卡车——一辆车只能一个人用,成本高、数量少(每个线程1MB内存,最多几千个)。虚拟线程是共享单车——几百万辆共享单车,成本极低(几百字节),随用随走
  • 结构化并发 = 团队协作有组长:以前多任务并行像“各干各的”,一个失败其他人还在瞎跑。现在像有组长的团队——组长统筹,一个子任务失败全部取消

🔬 JDK 17三大核心特性深度解析

1. Record类 —— 告别POJO样板代码

Record类是不可变数据载体,用一行代码替代几十行POJO代码。

// ❌ 传统POJO:几十行样板代码publicclassPoint{privatefinalintx;privatefinalinty;publicPoint(intx,inty){this.x=x;this.y=y;}publicintx(){returnx;}publicinty(){returny;}@Overridepublicbooleanequals(Objecto){/* ... */}@OverridepublicinthashCode(){/* ... */}@OverridepublicStringtoString(){/* ... */}}// ✅ Record:一行搞定publicrecordPoint(intx,inty){}// 自动生成:构造器、访问器(x()/y())、equals、hashCode、toString

Record的进阶用法

// 紧凑构造函数(参数校验)publicrecordPoint(intx,inty){publicPoint{if(x<0||y<0){thrownewIllegalArgumentException("坐标不能为负数");}}}// 实现接口publicinterfaceShape{doublearea();}publicrecordCircle(doubleradius)implementsShape{@Overridepublicdoublearea(){returnMath.PI*radius*radius;}}

使用场景:DTO、VO、值对象、API响应对象等纯数据载体。

2. 密封类 —— 精准控制继承边界

密封类通过sealed关键字和permits子句,明确指定哪些类可以继承它,让类型层次结构封闭可知。

// 定义密封类:只有Circle、Rectangle、Triangle可以继承sealedclassShapepermitsCircle,Rectangle,Triangle{}// 子类必须声明为final、sealed或non-sealedfinalclassCircleextendsShape{}finalclassRectangleextendsShape{}finalclassTriangleextendsShape{}

密封类的核心价值:与模式匹配结合,编译器能穷尽检查所有子类型,不再需要default分支。

3. 模式匹配 —— 简化类型判断与解构

instanceof模式匹配:判断类型的同时声明变量,消除强制转型。

// ❌ 传统写法if(objinstanceofString){Strings=(String)obj;// 还要强制转型System.out.println(s.length());}// ✅ 模式匹配if(objinstanceofStrings){// 直接声明变量sSystem.out.println(s.length());}

switch模式匹配:直接匹配类型,还能解构Record。

Stringdescribe(Shapeshape){returnswitch(shape){caseCirclec->"圆形,半径"+c.radius();caseRectangler->"矩形,"+r.length()+"x"+r.width();caseTrianglet->"三角形";};// 密封类保证穷尽,无需default}

🔬 JDK 21四大核心特性深度解析

1. 虚拟线程 —— 百万级并发革命

虚拟线程是JDK 21最具颠覆性的特性,由Project Loom孵化,目标是用同步代码写出异步的吞吐量。

核心对比

维度平台线程(传统)虚拟线程
底层映射1:1映射到OS线程M:N映射到少量平台线程
栈内存默认1MB初始几百字节,动态伸缩
最大并发数几千千万级
阻塞行为阻塞OS线程只阻塞虚拟线程,载体线程释放
创建成本约1µs + 1MB内存约1µs + 400字节内存

虚拟线程的核心机制

  • 虚拟线程由JVM调度,执行在少量载体线程(Carrier Thread)
  • 当虚拟线程执行阻塞I/O时,JVM自动挂起虚拟线程,释放载体线程给其他虚拟线程使用
  • I/O完成后,虚拟线程被重新调度到任意载体线程继续执行
  • 本质:虚拟线程 = 用户态线程 + JVM级调度器 + 自动挂载/卸载

基本用法

// 方式1:直接创建Threadvt=Thread.ofVirtual().start(()->{System.out.println("Hello from virtual thread!");});// 方式2:虚拟线程执行器(推荐)try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){for(inti=0;i<100_000;i++){executor.submit(()->{Thread.sleep(100);// 阻塞时自动释放载体线程returnnull;});}}// try-with-resources自动等待所有虚拟线程结束

压测数据:100万个虚拟线程同时sleep 1秒,仅需约1秒完成,内存峰值<1.5GB。

2. 结构化并发 —— 多任务协作有“组长”

传统并发中,子任务“各自为政”——一个失败其他还在跑,资源浪费。结构化并发让子任务与父任务生命周期绑定:父任务失败,所有子任务自动取消。

// 传统方式:需要手动管理Future和异常ExecutorServicees=Executors.newCachedThreadPool();Future<User>user=es.submit(()->fetchUser());Future<Order>order=es.submit(()->fetchOrder());// user失败,order还在继续执行...// 结构化并发try(varscope=newStructuredTaskScope.ShutdownOnFailure()){Future<User>user=scope.fork(()->fetchUser());Future<Order>order=scope.fork(()->fetchOrder());scope.join();// 等待所有子任务scope.throwIfFailed();// 任一失败抛出异常// 全部成功才继续}// 自动取消所有子任务

3. 顺序集合 & 作用域值

顺序集合:统一了ListDequeSortedSet等有序集合的操作接口,新增reversed()getFirst()getLast()等方法。

作用域值:替代ThreadLocal,与虚拟线程更兼容,按调用栈传递数据。

🔍 高频面试追问(5道大厂真题)

追问1:虚拟线程和平台线程的本质区别是什么?

回答要点:虚拟线程是JVM调度的用户态线程,不绑定OS线程;平台线程1:1映射到OS线程。

详细回答

平台线程是重量级的——每个线程默认1MB栈内存,创建数量受OS限制(通常几千个)。虚拟线程是轻量级的——由JVM调度,初始栈仅几百字节,单机可支撑百万级并发。虚拟线程阻塞I/O时会自动释放载体线程,不浪费OS资源。

追问2:虚拟线程适合什么场景?不适合什么场景?

回答要点:适合IO密集型,不适合CPU密集型。

详细回答

✅ 适合:高并发IO密集型任务(Web服务、RPC调用、数据库查询、微服务网关)——阻塞等待时自动释放载体线程。

❌ 不适合:CPU密集型任务——虚拟线程无法加速计算,大量上下文切换反而降低性能。也不适合synchronized深度嵌套的遗留代码,可能阻塞载体线程。

追问3:Record类和普通类有什么区别?

回答要点:Record是透明不可变的数据载体,自动生成所有标准方法。

详细回答

Record类自动生成构造器、访问器、equalshashCodetoString。所有字段默认private final,强制不可变。Record隐式继承java.lang.Record,不能继承其他类。适合DTO/VO/值对象等纯数据载体。

追问4:密封类和模式匹配如何配合使用?

回答要点:密封类让编译器知道所有子类型,模式匹配做穷尽检查,无需default。

详细回答

密封类通过permits明确指定所有可能的子类。配合模式匹配的switch,编译器能穷尽检查所有子类型——如果漏掉某个子类的case,编译报错。这大幅提升了类型安全性。

追问5:为什么说虚拟线程是“用同步代码写出异步吞吐量”?

回答要点:虚拟线程让阻塞I/O不再阻塞平台线程,代码保持同步风格。

详细回答

传统异步编程(Netty、CompletableFuture)虽吞吐量高,但代码是“回调地狱”或“链式调用”,调试困难。虚拟线程让每个请求占用一个虚拟线程,执行阻塞I/O时JVM自动挂起并释放载体线程。开发者写的是简单的同步代码,底层自动实现了异步的高吞吐。

💣 避坑指南

序号错误做法正确做法后果
1在CPU密集型任务中大量使用虚拟线程CPU密集型用平台线程或保持线程数≈CPU核心数上下文切换开销大,性能下降
2在synchronized深度嵌套中使用虚拟线程用ReentrantLock或减少锁嵌套深度可能阻塞载体线程
3用Record类做可变业务实体Record用于不可变数据载体违背设计意图,代码混乱
4升级到JDK 17/21时不做兼容测试逐步升级,测试遗留框架兼容性反射、字节码库可能不兼容

💻 可运行验证代码

// ===== Record类 =====publicrecordUser(Longid,Stringname,Stringemail){}// ===== 密封类 + 模式匹配 =====sealedinterfaceShapepermitsCircle,Rectangle{}publicrecordCircle(doubleradius)implementsShape{}publicrecordRectangle(doublew,doubleh)implementsShape{}Stringdescribe(Shapes){returnswitch(s){caseCirclec->"圆,半径="+c.radius();caseRectangler->"矩形,"+r.w()+"x"+r.h();};}// ===== 虚拟线程 =====try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){IntStream.range(0,10_000).forEach(i->executor.submit(()->{Thread.sleep(100);System.out.println("Task "+i+" done");returnnull;}));}

❓ 评论区挑战

问题:以下关于虚拟线程的说法,哪一个是错误的?

// 创建虚拟线程Threadvt=Thread.ofVirtual().start(()->{Thread.sleep(1000);});

A. 虚拟线程由JVM调度,不直接绑定操作系统线程
B. 虚拟线程阻塞I/O时会释放载体线程给其他虚拟线程使用
C. 虚拟线程适合CPU密集型任务,能大幅提升计算性能
D. 一个Java进程可以创建百万级虚拟线程

💬 欢迎在评论区写出你的答案和理由,我会在下一篇文章发布后更新本文,公布答案及错误选项逐项解析。

✅ 答案公布

正确答案:C. 虚拟线程适合CPU密集型任务,能大幅提升计算性能

解析

  • 虚拟线程的优势在IO密集型场景——阻塞时释放载体线程,提高资源利用率
  • CPU密集型任务中,虚拟线程无法加速计算,大量上下文切换反而降低性能
  • 选项A正确:虚拟线程由JVM调度
  • 选项B正确:阻塞I/O时自动释放载体线程
  • 选项D正确:虚拟线程可支撑百万级并发

📌 总结

版本特性一句话概括核心价值
JDK 17Record类一行代码定义不可变数据载体消除POJO样板代码
JDK 17密封类精准控制继承边界类型层次封闭可知
JDK 17模式匹配简化类型判断与数据解构消除强制转型,提升安全性
JDK 21虚拟线程轻量级用户态线程,百万并发同步代码异步吞吐
JDK 21结构化并发子任务与父任务生命周期绑定自动取消,异常统一处理

面试官最看重的三个点

  1. JDK 17 vs 21的定位差异:JDK 17让代码更简洁安全,JDK 21让并发更轻量强大
  2. 虚拟线程适用场景:IO密集型✅ / CPU密集型❌——能准确区分
  3. 现代Java特性组合:Record+密封类+模式匹配可构建类型安全的领域模型

📚 系列导航

  • 上一篇:面试官问:序列化与反序列化(含框架对比)?
  • 下一篇预告:面试官问:Java模块化(Project Jigsaw)与反射限制?(待发布)
  • 全部85题目录:点击查看(关注专栏,每周2-3篇,一键追更

📘搭配学习效果更佳

本篇图解帮你快速建立知识画面记忆,如果想深入理解源码实现和实战避坑细节,可以配合姊妹系列《Java 100天进阶之路》对应章节一起学:

从零基础到上岗就业,108篇完整学习地图,每篇标配生活类比 + 可运行代码 + 避坑表 + 面试高频题 + 练习题,不背八股文,真正讲透“为什么”。

👉 《Java 100天进阶之路》完整目录导航

学习建议:图解系列负责“快速建立知识图谱”,进阶系列负责“深入理解原理”,两个系列搭配使用,面试备考效率翻倍。

💬你们公司升级到JDK 17或21了吗?虚拟线程在生产环境用得怎么样?欢迎评论区分享你的实践经验~