核心新特性概览
1. 密封类(Sealed Classes)- JEP 409
// 定义密封类
public sealed class Shape
permits Circle, Rectangle, Triangle {
// 父类定义
}
// 子类必须是 final、sealed 或 non-sealed
public final class Circle extends Shape {
private final double radius;
}
public sealed class Rectangle extends Shape
permits Square {
protected final double length, width;
}
public non-sealed class Triangle extends Shape {
// 可以被任意继承
}
public final class Square extends Rectangle {
// Square 是 Rectangle 的最终子类
}
面试要点:
- 目的:限制类的继承,明确类层次结构。
- 三个修饰符:
sealed、final、non-sealed。
- 用途:
- 模式匹配中的穷尽性检查。
- 替代枚举的扩展需求。
- API 设计时控制扩展性。
// 使用密封类实现扩展的“枚举”
public sealed interface Expr
permits ConstantExpr, PlusExpr, TimesExpr, NegExpr {
double eval();
}
public record ConstantExpr(double value) implements Expr {
public double eval() { return value; }
}
public record PlusExpr(Expr left, Expr right) implements Expr {
public double eval() { return left.eval() + right.eval(); }
}
// 编译时检查穷尽性
double evaluate(Expr expr) {
return switch (expr) {
case ConstantExpr(var value) -> value;
case PlusExpr(var left, var right) -> left.eval() + right.eval();
case TimesExpr(var left, var right) -> left.eval() * right.eval();
case NegExpr(var operand) -> -operand.eval();
// 不需要 default,因为所有情况已覆盖
};
}
2. 模式匹配增强(Pattern Matching)
2.1 Switch 模式匹配(预览)- JEP 406
// 传统 switch
static String formatter(Object obj) {
if (obj instanceof Integer i) {
return String.format("int %d", i);
} else if (obj instanceof Long l) {
return String.format("long %d", l);
} else if (obj instanceof Double d) {
return String.format("double %f", d);
}
return obj.toString();
}
// Switch 模式匹配
static String formatterPatternSwitch(Object obj) {
return switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
case null -> "null";
default -> obj.toString();
};
}
// 复杂的模式匹配
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.getArea() > 100) ->
System.out.println("Large triangle");
case Triangle t ->
System.out.println("Small triangle");
case Circle c ->
System.out.println("Circle");
default ->
System.out.println("Unknown shape");
}
}
3. 新的 macOS 渲染管道
// 自动使用 Metal 框架替代 OpenGL
// 无需代码更改,JVM 自动处理
// 如果需要,可以指定渲染器
java -Dsun.java2d.metal=true MyApplication
改进:
- 更好的性能。
- 更好的兼容性(macOS 已弃用 OpenGL)。
- 减少内存占用。
4. 增强的伪随机数生成器(Enhanced Pseudo-Random Number Generators)- JEP 356
// 新的接口 RandomGenerator
import java.util.random.*;
// 获取默认的随机数生成器
RandomGenerator generator = RandomGenerator.getDefault();
// 获取特定算法
RandomGenerator l64x128 = RandomGenerator.of("L64X128MixRandom");
// 流式操作
RandomGenerator.StreamableGenerator streamable =
RandomGenerator.SplittableGenerator.of("L128X1024MixRandom");
// 生成随机数流
generator.ints(10, 0, 100)
.forEach(System.out::println);
可用算法:
- L32X64MixRandom
- L64X128MixRandom
- L64X128StarStarRandom
- L64X256MixRandom
- L128X128MixRandom
- L128X256MixRandom
5. 外部函数和内存 API(Foreign Function & Memory API)- JEP 412
// 访问本地内存(预览功能)
import jdk.incubator.foreign.*;
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
// 分配内存
MemorySegment segment = MemorySegment.allocateNative(
100, scope);
// 设置值
MemoryAccess.setInt(segment, 0, 42);
// 获取值
int value = MemoryAccess.getInt(segment, 0);
}
// 调用本地函数
CLinker linker = CLinker.getInstance();
MethodHandle strlen = linker.downcallHandle(
linker.lookup("strlen").get(),
FunctionDescriptor.of(CLinker.C_LONG, CLinker.C_POINTER)
);
特性:
- 替代 JNI 的更安全、高性能方案。
- 与 Project Panama 相关。
- 仍在孵化阶段。
6. 上下文特定的反序列化过滤器(Context-Specific Deserialization Filters)- JEP 415
// 创建反序列化过滤器
ObjectInputFilter filter =
ObjectInputFilter.Config.createFilter(
"maxdepth=10;java.base/*;!*"
);
// 为特定流设置过滤器
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);
// 设置全局过滤器
ObjectInputFilter.Config.setSerialFilter(filter);
安全特性:
- 防止反序列化攻击。
- 细粒度控制允许/拒绝的类。
- 可以在运行时动态调整。
7. 新的 macOS/AArch64 端口
// 支持 Apple Silicon(M1/M2 芯片)
// 提供原生 ARM 64 位支持
// 检查架构
System.out.println(System.getProperty("os.arch"));
// 输出:aarch64 (Apple Silicon)
8. 移除的特性
8.1 移除实验性 AOT 和 JIT 编译器
# 不再支持以下选项
java -XX:+UseAOT
java -XX:AOTLibrary
# 移除的模块
java -p $JAVA_HOME/lib/jdk.internal.vm.compiler
8.2 移除 Applet API
// 以下类已移除
// java.applet.Applet
// javax.swing.JApplet
8.3 弃用安全管理器(Deprecate)
// SecurityManager 已标记为弃用
SecurityManager manager = System.getSecurityManager();
// 将来版本可能移除
语言特性深度解析
密封类的使用场景
- 场景1:替代枚举的扩展需求。
- 场景2:API 设计中的受控继承。
// 网络协议消息设计
public sealed interface Message
permits LoginMessage, ChatMessage, LogoutMessage {
String getSessionId();
}
// 只允许这三种消息类型
public record LoginMessage(String sessionId, String username)
implements Message {}
public record ChatMessage(String sessionId, String content)
implements Message {}
public record LogoutMessage(String sessionId)
implements Message {}
高频面试问题
Q1: 密封类的主要优势是什么?
答:
- 编译时检查:确保所有 permitted 子类都被处理。
- 代码清晰:明确显示类的继承结构。
- 模式匹配友好:与 switch 表达式完美配合。
- API 设计:控制第三方扩展,保持向后兼容。
Q2: Switch 模式匹配相比 if-else 的优势?
答:
| 特性 |
传统 if-else |
Switch 模式匹配 |
| 可读性 |
嵌套复杂 |
结构清晰 |
| 穷尽性检查 |
需要手动处理 |
编译器自动检查 |
| 空值处理 |
需要额外检查 |
直接支持 case null |
| 性能 |
线性检查 |
可能优化为跳转表 |
Q3: 为什么移除 Applet 和安全管理器?
答:
Applet:
- 浏览器不再支持 Java 插件。
- Web 技术发展(HTML5、WebAssembly)。
- 安全风险和维护成本。
安全管理器:
- 复杂且难以正确使用。
- 现代安全模型(容器化、模块化)。
- 替代方案:Java 模块系统、操作系统容器。
Q4: 新的随机数生成器有什么改进?
答:
- 标准化接口:统一了 Random 类的各种变体。
- 算法选择:提供多种现代算法。
- 性能优化:更好的统计特性。
- 流式支持:直接生成随机数流。
Q5: Foreign Function & Memory API 的意义?
答:
- 替代 JNI:更简单、更安全的本地代码交互。
- 性能提升:减少 JNI 开销。
- 内存安全:防止内存泄漏和非法访问。
- 为 Project Panama 铺路:改进 Java 与原生代码的互操作。
代码实战题
题1: 使用密封类和模式匹配
// 定义表达式体系
sealed interface Expr
permits NumberExpr, AddExpr, MultiplyExpr {
int evaluate();
}
record NumberExpr(int value) implements Expr {
public int evaluate(){ return value; }
}
record AddExpr(Expr left, Expr right) implements Expr {
public int evaluate(){
return left.evaluate() + right.evaluate();
}
}
record MultiplyExpr(Expr left, Expr right) implements Expr {
public int evaluate(){
return left.evaluate() * right.evaluate();
}
}
// 使用模式匹配处理表达式
String format(Expr expr){
return switch (expr) {
case NumberExpr(var n) -> String.valueOf(n);
case AddExpr(var l, var r) ->
String.format("(%s + %s)", format(l), format(r));
case MultiplyExpr(var l, var r) ->
String.format("%s * %s", format(l), format(r));
};
}
题2: 随机数生成器性能测试
public class RandomBenchmark {
public static void main(String[] args) {
// 测试不同算法的性能
String[] algorithms = {
"Random", "SecureRandom",
"L64X128MixRandom", "L128X256MixRandom"
};
for (String algo : algorithms) {
long start = System.nanoTime();
RandomGenerator gen = RandomGenerator.of(algo);
long sum = 0;
for (int i = 0; i < 1_000_000; i++) {
sum += gen.nextInt(100);
}
long duration = System.nanoTime() - start;
System.out.printf("%s: %d ms%n", algo, duration / 1_000_000);
}
}
}
迁移和兼容性
迁移注意事项
- 模块化应用:检查对内部 API 的访问。
- 序列化:更新反序列化过滤器配置。
- 安全代码:准备 SecurityManager 的替代方案。
- 构建工具:更新 Maven/Gradle 配置。
兼容性影响
// 1. 反射访问 sealed 类
Class<Shape> shapeClass = Shape.class;
boolean isSealed = shapeClass.isSealed(); // true
Class<?>[] permitted = shapeClass.getPermittedSubclasses();
// 2. 模式匹配的向后兼容
// 现有的 instanceof 代码仍然工作
if (obj instanceof String) {
String s = (String) obj;
// 可以逐步改为模式匹配
}
// 3. 随机数生成器的兼容性
Random oldRandom = new Random();
RandomGenerator newRandom = RandomGenerator.getDefault();
// Random 实现了 RandomGenerator 接口
最佳实践建议
1. 密封类使用建议
- 在 API 设计中优先使用密封接口。
- 为每个 permitted 子类添加充分的文档。
- 结合记录类(record)使用效果更佳。
2. 模式匹配最佳实践
// 使用守卫条件(Guard)
static void test(Object obj) {
switch (obj) {
case String s when s.length() > 5 ->
System.out.println("Long string: " + s);
case String s ->
System.out.println("Short string: " + s);
case null ->
System.out.println("Null value");
default ->
System.out.println("Other: " + obj);
}
}
3. 随机数选择指南
- 默认:L32X64MixRandom(平衡性能和质量)。
- 高性能:Xoroshiro128PlusPlus。
- 高质量:L64X1024MixRandom。
- 加密安全:继续使用 SecureRandom。
面试准备要点
必须掌握的:
- 密封类的定义和使用场景。
- Switch 模式匹配语法。
- 新随机数生成器 API。
需要理解的:
- 密封类与枚举的区别。
- 模式匹配的编译器优化。
- 外部函数 API 的设计理念。
了解即可的:
- macOS 渲染管道细节。
- 反序列化过滤器的配置语法。
- 已移除特性的历史背景。
对于正在准备Java面试的开发者来说,JDK 17作为最新的 LTS 版本,代表了 Java 语言的现代化方向。掌握这些新特性不仅能帮你从容应对技术提问,更能指导你写出更安全、更清晰、更高效的 Java 代码。如果你想了解更多技术细节或与同行交流,欢迎访问云栈社区的相关板块进行深入探讨。