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

TypeScript中如何限制Set仅保留同一Spell子类的单个实例?

解决方案

方案1:重写Spell类的equals()和hashCode()方法

Set的去重逻辑完全依赖元素的equals()和hashCode()方法,默认的Object实现是比较对象引用,所以不同实例会被判定为不同元素。我们可以让这两个方法基于类的类型来判断,这样同一子类的所有实例都会被视为相同元素:

public abstract class Spell {
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        // 若Spell有需要参与判定的属性,可在此补充逻辑
        return true;
    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }
}

修改后,同一子类的不同实例会被Set判定为重复,不会被多次添加。

方案2:将Spell子类实现为单例

如果每个法术类型本身只应该存在一个实例,直接把Fireball、Lightning做成单例,这样每次添加的都是同一个对象引用,Set自然会自动去重:

饿汉式单例实现

public class Fireball extends Spell {
    private static final Fireball INSTANCE = new Fireball();

    private Fireball() {}

    public static Fireball getInstance() {
        return INSTANCE;
    }
}

public class Lightning extends Spell {
    private static final Lightning INSTANCE = new Lightning();

    private Lightning() {}

    public static Lightning getInstance() {
        return INSTANCE;
    }
}

使用时调用Fireball.getInstance()获取实例添加到Set,无论调用多少次,都是同一个对象,不会出现重复存储的问题。

方案3:用枚举类替代子类

如果法术类型是固定的有限个(比如只有Fireball和Lightning),用枚举实现是最简洁的方案——枚举天然是单例,且自带正确的equals()和hashCode()实现:

public enum Spell {
    FIREBALL,
    LIGHTNING;

    // 可添加法术的核心方法,比如施法逻辑
    public abstract void cast();

    @Override
    public void cast() {
        switch(this) {
            case FIREBALL:
                System.out.println("释放火球术");
                break;
            case LIGHTNING:
                System.out.println("释放闪电术");
                break;
        }
    }
}

此时Character的spells属性定义为Set<Spell>,直接添加Spell.FIREBALL即可,完全不会出现重复问题。


内容的提问来源于stack exchange,提问作者Michael Moreno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:13:15