You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何表示不相交联合类型并限制实现类的范围?

方案1:Java 16+ 密封类(最优解)

Java 16引入的sealed(密封)语法就是专门为这类「固定子类数量的不相交联合类型」设计的,完美解决你提到的两个痛点:既限制了仅允许指定类型实现接口,也大幅简化了模式匹配的代码,不需要再写冗长的访问者实现。

示例代码如下:

// permits关键字明确指定仅允许Cash、CreditCard两个类实现该接口,外部类无法自定义实现
public sealed interface PaymentMethod permits Cash, CreditCard {}

// 实现类声明为final,禁止再被继承扩展
public final class Cash implements PaymentMethod {}

public final class CreditCard implements PaymentMethod {
    private final String accountNum;

    public CreditCard(String accountNum) {
        this.accountNum = accountNum;
    }

    public String getAccountNum() {
        return accountNum;
    }
}

如果使用Java 17及以上版本,还可以配合switch模式匹配直接做分支判断,编译器会自动检查所有分支是否覆盖,漏写会直接触发编译错误:

public String getPaymentInfo(PaymentMethod method) {
    return switch (method) {
        case Cash cash -> "现金支付";
        case CreditCard card -> String.format("信用卡支付,卡号:%s", card.getAccountNum());
    };
}

方案2:Java 8~15 兼容方案

如果你的项目暂时无法升级到Java 16以上,可以用「私有构造抽象类+内部静态子类」的方式实现相同的限制效果:抽象类的构造函数设为私有后,只有同一个类内部的子类可以调用父类构造,外部类无法继承该抽象类,自然也不能自定义实现。

示例代码如下:

import java.util.function.Function;

public abstract class PaymentMethod {
    // 私有构造,禁止外部类继承
    private PaymentMethod() {}

    // 提供匹配方法,替代访问者模式,使用更简洁
    public abstract <R> R match(
        Function<Cash, R> onCash,
        Function<CreditCard, R> onCreditCard
    );

    public static final class Cash extends PaymentMethod {
        @Override
        public <R> R match(Function<Cash, R> onCash, Function<CreditCard, R> onCreditCard) {
            return onCash.apply(this);
        }
    }

    public static final class CreditCard extends PaymentMethod {
        private final String accountNum;

        public CreditCard(String accountNum) {
            this.accountNum = accountNum;
        }

        public String getAccountNum() {
            return accountNum;
        }

        @Override
        public <R> R match(Function<Cash, R> onCash, Function<CreditCard, R> onCreditCard) {
            return onCreditCard.apply(this);
        }
    }
}

使用时只需传入两个分支的处理逻辑即可,不需要额外实现访问者接口:

String info = paymentMethod.match(
    cash -> "现金支付",
    card -> String.format("信用卡支付,卡号:%s", card.getAccountNum())
);

内容的提问来源于stack exchange,提问作者TJ Mazeika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 13:36:06