Java密封类在实际中怎么用

wen java案例 1

本文目录导读:

Java密封类在实际中怎么用

  1. 核心用途:精确控制继承体系
  2. 基本语法结构
  3. 实际项目场景示例
  4. 关键注意事项

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)
  • 如果不在同一包,必须放在同一模块内
  • 每个子类必须显式声明为 finalsealednon-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迈向更安全、更可维护代码的重要一步。

抱歉,评论功能暂时关闭!