本文目录导读:

Java密封类(Sealed Class)是Java 17正式引入的一个特性,它提供了一种比final更灵活的继承控制方式,下面是实际开发中的典型使用场景和具体代码示例。
核心用途:精确控制继承体系
密封类允许你声明一个类或接口,明确指定哪些其他类或接口可以继承或实现它,这对以下场景特别有价值:
- 领域建模:如状态机、支付方式、用户角色等有限子集
- 模式匹配:配合
switch表达式实现穷举匹配 - API设计:防止用户意外扩展你的核心类层次结构
基本语法结构
// 定义密封接口
public sealed interface Vehicle permits Car, Truck, Motorcycle {
int getMaxSpeed();
}
// 必须声明为 final、sealed 或 non-sealed
public final class Car implements Vehicle {
@Override
public int getMaxSpeed() {
return 200;
}
}
public final class Truck implements Vehicle {
@Override
public int getMaxSpeed() {
return 120;
}
}
// 允许继续扩展
public non-sealed class Motorcycle implements Vehicle {
@Override
public int getMaxSpeed() {
return 250;
}
}
实际项目场景示例
场景1:状态机(订单状态)
// 定义密封的订单状态
public sealed interface OrderState
permits Pending, Confirmed, Shipped, Delivered, Cancelled {
boolean canTransitionTo(OrderState target);
String getDisplayName();
}
// 各个具体状态
public final class Pending implements OrderState {
@Override
public boolean canTransitionTo(OrderState target) {
return target instanceof Confirmed || target instanceof Cancelled;
}
@Override
public String getDisplayName() {
return "待确认";
}
}
public final class Confirmed implements OrderState {
@Override
public boolean canTransitionTo(OrderState target) {
return target instanceof Shipped || target instanceof Cancelled;
}
@Override
public String getDisplayName() {
return "已确认";
}
}
// ... 其他状态类类似
// 使用密封类配合 switch 穷举
public boolean processOrderState(OrderState current, OrderState target) {
// 编译器可以保证覆盖所有状态
String message = switch (current) {
case Pending p -> {
System.out.println("处理待确认订单");
yield p.canTransitionTo(target) ? "可以转换" : "不能转换";
}
case Confirmed c -> {
System.out.println("处理已确认订单");
yield c.canTransitionTo(target) ? "可以转换" : "不能转换";
}
case Shipped s -> {
System.out.println("处理运输中订单");
yield s.canTransitionTo(target) ? "可以转换" : "不能转换";
}
case Delivered d -> "订单已完成,不能转换";
case Cancelled c -> "订单已取消,不能转换";
};
return "可以转换".equals(message);
}
场景2:支付方式处理
// 密封的支付方式接口
public sealed interface PaymentMethod
permits CreditCard, DebitCard, Alipay, WeChatPay {
boolean processPayment(double amount);
String getPaymentType();
}
// 信用卡支付
public final class CreditCard implements PaymentMethod {
private final String cardNumber;
private final String cvv;
public CreditCard(String cardNumber, String cvv) {
this.cardNumber = cardNumber;
this.cvv = cvv;
}
@Override
public boolean processPayment(double amount) {
System.out.println("信用卡支付:" + amount);
return true;
}
@Override
public String getPaymentType() {
return "信用卡";
}
}
// 支付宝支付
public final class Alipay implements PaymentMethod {
private final String userId;
public Alipay(String userId) {
this.userId = userId;
}
@Override
public boolean processPayment(double amount) {
System.out.println("支付宝支付:" + amount);
return true;
}
@Override
public String getPaymentType() {
return "支付宝";
}
}
// ... 其他支付方式类似
// 支付处理器,利用密封类保证穷举
public class PaymentProcessor {
public String getPaymentDescription(PaymentMethod payment) {
// 编译器会检查是否覆盖了所有支付方式
return switch (payment) {
case CreditCard c -> "信用卡支付 - " + c.getPaymentType();
case DebitCard d -> "借记卡支付 - " + d.getPaymentType();
case Alipay a -> "支付宝支付 - " + a.getPaymentType();
case WeChatPay w -> "微信支付 - " + w.getPaymentType();
};
}
public boolean pay(PaymentMethod method, double amount) {
System.out.println("使用" + method.getPaymentType() + "支付");
return method.processPayment(amount);
}
}
场景3:表达式解析器(AST节点)
// 密封的表达式节点
public sealed interface Expression
permits NumberExpr, BinaryExpr, UnaryExpr, VariableExpr {
int evaluate(Context context);
}
// 数字表达式
public final class NumberExpr implements Expression {
private final int value;
public NumberExpr(int value) {
this.value = value;
}
@Override
public int evaluate(Context context) {
return value;
}
}
// 二元操作表达式
public final class BinaryExpr implements Expression {
private final Expression left;
private final Expression right;
private final String operator;
public BinaryExpr(Expression left, Expression right, String operator) {
this.left = left;
this.right = right;
this.operator = operator;
}
@Override
public int evaluate(Context context) {
return switch (operator) {
case "+" -> left.evaluate(context) + right.evaluate(context);
case "-" -> left.evaluate(context) - right.evaluate(context);
case "*" -> left.evaluate(context) * right.evaluate(context);
case "/" -> left.evaluate(context) / right.evaluate(context);
default -> throw new IllegalArgumentException("未知操作符");
};
}
}
// ... 其他表达式类型
// 表达式计算器
public class ExpressionEvaluator {
public String describeExpression(Expression expr) {
// 穷举匹配,编译器保证
return switch (expr) {
case NumberExpr n -> "常量: " + n.evaluate(null);
case BinaryExpr b -> "二元操作";
case UnaryExpr u -> "一元操作";
case VariableExpr v -> "变量引用";
};
}
}
关键注意事项
继承要求
- 所有允许的子类必须与密封类在同一个模块中(Java 17)
- 如果不在同一包,必须放在同一模块内
- 每个子类必须显式声明为
final、sealed或non-sealed
模块系统配合
// 在 module-info.java 中导出密封类
module com.example.payments {
exports com.example.payments.model; // 包含密封类 PaymentMethod
exports com.example.payments.impl; // 包含实现类
}
与记录类(Record)结合
// 记录类天然是 final 的,非常适合作为密封类的子类
public sealed interface Shape permits Circle, Rectangle, Triangle { }
public record Circle(double radius) implements Shape { }
public record Rectangle(double width, double height) implements Shape { }
public record Triangle(double base, double height) implements Shape { }
什么时候使用密封类?
- 你的领域模型有明确的有限子类型集合
- 需要编译器保证 switch 表达式的穷举性
- 设计框架或API时,希望控制用户扩展的范围
- 状态机、表达式树、命令模式等场景
什么时候不要用?
- 子类型可能由第三方扩展(如插件系统)
- 子类型数量可能动态增长
- 与现有的非密封类层次结构集成
密封类让继承关系变得可预测和可控,是Java迈向更安全、更可维护代码的重要一步。