以下是对Java中**密封类(Sealed Classes)和记录类(Record Classes)**的详细讲解,结合代码示例与核心特性:
一、密封类(Sealed Classes)
密封类用于限制类的继承关系,明确指定哪些类可以继承或实现它,增强代码的可控性和安全性。自Java 17起成为正式特性。
1. 核心语法
- 使用
sealed
关键字声明密封类。 - 通过
permits
指定允许继承的子类。 - 子类必须使用
final
、sealed
或non-sealed
修饰符。
示例代码
// 密封类声明
public sealed class Shape permits Circle, Rectangle, Triangle {
public abstract double area();
}
// 子类必须明确修饰符
final class Circle extends Shape {
private final double radius;
public Circle(double r) { this.radius = r; }
@Override public double area() { return Math.PI * radius * radius; }
}
non-sealed class Rectangle extends Shape {
private final double width, height;
public Rectangle(double w, double h) { this.width = w; this.height = h; }
@Override public double area() { return width * height; }
}
sealed class Triangle extends Shape permits EquilateralTriangle {
protected double base, height;
@Override public double area() { return 0.5 * base * height; }
}
final class EquilateralTriangle extends Triangle {
public EquilateralTriangle(double side) {
this.base = side;
this.height = (Math.sqrt(3)/2) * side;
}
}
2. 关键规则
- 继承限制:只有
permits
列出的类可以继承密封类。 - 子类修饰符:
final
:禁止进一步继承。sealed
:子类继续密封,需指定新的permits
列表。non-sealed
:解除密封限制,允许任意继承。
- 包与模块:密封类及其子类需位于同一包或模块中。
3. 应用场景
- 精确建模:如几何形状仅允许特定子类。
- 模式匹配:结合
switch
表达式确保所有子类覆盖。 - API设计:限制第三方扩展,避免不可控继承。
二、记录类(Record Classes)
记录类用于简化不可变数据类的定义,自动生成构造函数、访问器和工具方法(如equals
、hashCode
)。自Java 16起成为正式特性。
1. 核心语法
- 使用
record
关键字声明。 - 组件(字段)隐式声明为
private final
。 - 自动生成规范构造函数、
toString()
、equals()
和hashCode()
。
示例代码
// 声明记录类
public record Person(String name, int age) {
// 可添加静态字段或方法
public static final int MAX_AGE = 120;
// 紧凑构造函数(参数校验)
public Person {
if (age < 0 || age > MAX_AGE) {
throw new IllegalArgumentException("Invalid age");
}
}
// 自定义实例方法
public String greet() {
return "Hello, I'm " + name;
}
}
// 使用记录类
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice", 30);
Person p2 = new Person("Bob", 25);
System.out.println(p1.name()); // 输出:Alice
System.out.println(p1.equals(p2)); // 输出:false
System.out.println(p1.greet()); // 输出:Hello, I'm Alice
}
}
2. 关键特性
- 不可变性:所有字段为
final
,无Setter方法。 - 构造函数:
- 规范构造函数:参数与组件列表一致。
- 紧凑构造函数:无需参数列表,直接校验或处理字段。
- 非规范构造函数:必须调用其他构造函数(通过
this()
)。
- 限制:
- 不能继承其他类,但可实现接口。
- 所有非组件字段必须为
static
。
3. 应用场景
- DTO(数据传输对象):如API响应数据载体。
- 值对象:如坐标点、日期范围等不可变数据。
- 模式匹配:与
instanceof
结合简化类型判断。
三、密封类与记录类的对比
特性 | 密封类(Sealed Classes) | 记录类(Record Classes) |
---|---|---|
设计目的 | 限制继承关系,明确子类范围 | 简化不可变数据类的定义 |
关键字 | sealed , permits | record |
不可变性 | 不强制(依赖子类实现) | 隐式不可变(字段为final ) |
主要应用 | 模式匹配、API设计 | 数据载体、DTO |
版本支持 | Java 17+ | Java 16+ |
四、进阶用法与最佳实践
1. 密封类结合记录类
// 密封类定义形状
public sealed interface Shape permits Circle, Rectangle {
double area();
}
// 记录类实现密封接口
public record Circle(double radius) implements Shape {
@Override public double area() { return Math.PI * radius * radius; }
}
public record Rectangle(double width, double height) implements Shape {
@Override public double area() { return width * height; }
}
2. 模式匹配优化
// 结合密封类与模式匹配
public static void printArea(Shape shape) {
if (shape instanceof Circle c) {
System.out.println("Circle area: " + c.area());
} else if (shape instanceof Rectangle r) {
System.out.println("Rectangle area: " + r.area());
}
}
3. 序列化支持
记录类可序列化(实现Serializable
):
record GPS(double latitude, double longitude) implements Serializable {}
// 序列化与反序列化
GPS loc = new GPS(10, 20);
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("gps.obj"))) {
oos.writeObject(loc);
}
五、总结
- 密封类通过继承限制提升代码安全性,适用于需要明确子类范围的场景。
- 记录类通过减少样板代码提升开发效率,适用于不可变数据建模。
- 结合使用:两者可协同工作(如密封接口+记录实现),构建高表达力的领域模型。
参考资料: