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

如何限制StringIntTable使用者仅调用指定put方法,禁用父类HashMap相关方法

如何限制自定义哈希表仅允许调用指定的put方法?

我实现了一个StringIntTable类,核心用途是为不同字符串生成唯一整数,实现完美最小哈希。最初采用继承HashMap<String, Integer>的方式,自定义了一个put(final String string)方法来生成唯一映射,但发现使用者如果调用父类的put(K key, V value)、putAll等方法,会直接破坏哈希的唯一性规则。下面分析现有方案并给出更优解:


1. 继承HashMap的问题

继承方式虽然能直接复用get、size等HashMap原生方法,但无法阻止用户调用父类的修改方法。比如用户可以直接调用stringIntTable.put("test", 999),插入或覆盖不符合规则的键值对,完全违背设计初衷。

示例代码:

public class StringIntTable extends HashMap<String, Integer> {
    public int put(final String string) {
        return super.computeIfAbsent(string, v -> super.size() + 1);
    }
}

2. 适配器模式的优缺点

采用组合而非继承的适配器模式,能彻底隔离HashMap的原生修改方法,只暴露我们允许的操作,但缺点是需要手动实现原本可以直接复用的查询方法。

修正后代码(修复原代码泛型错误):

public class StringIntTable {
    private final HashMap<String, Integer> stringLookup = new HashMap<>();

    public int put(final String string) {
        return stringLookup.computeIfAbsent(string, v -> stringLookup.size() + 1);
    }

    // 手动实现需要的查询方法
    public Integer lookup(final String string) {
        return stringLookup.get(string);
    }

    public int size() {
        return stringLookup.size();
    }

    public boolean containsString(final String string) {
        return stringLookup.containsKey(string);
    }

    // 如需更多查询方法,按需添加
}
  • 优点:完全控制对外暴露的方法,用户无法调用任何破坏规则的操作;
  • 缺点:需要重复实现HashMap的部分方法,增加代码量。

3. 更优折中方案:继承+重写父类方法抛异常

如果不想写太多适配器的重复代码,又想阻止用户调用危险方法,可以继承HashMap后,重写所有会修改映射的父类方法并抛出异常,只保留自定义的put方法可用。

示例代码:

public class StringIntTable extends HashMap<String, Integer> {
    public int put(final String string) {
        return super.computeIfAbsent(string, v -> super.size() + 1);
    }

    // 重写父类put方法,禁止调用
    @Override
    public Integer put(String key, Integer value) {
        throw new UnsupportedOperationException("请使用put(String)方法添加元素");
    }

    // 禁止批量添加
    @Override
    public void putAll(Map<? extends String, ? extends Integer> m) {
        throw new UnsupportedOperationException("不允许批量添加元素");
    }

    // 禁止删除元素(若设计不允许删除)
    @Override
    public Integer remove(Object key) {
        throw new UnsupportedOperationException("不允许删除元素");
    }

    // 禁止清空表
    @Override
    public void clear() {
        throw new UnsupportedOperationException("不允许清空表");
    }
}

这种方案的优势:

  • 复用了HashMap的get、size、containsKey等查询方法,无需手动实现;
  • 明确阻止所有破坏哈希规则的操作,调用时会抛出清晰的异常提示;
  • 保留核心的自定义put方法,符合设计初衷。

注:如果业务允许删除元素,可以不重写remove和clear,但需注意删除后size变化可能导致后续生成的整数重复(完美最小哈希通常不支持删除操作)。


总结

  • 追求绝对封装安全:优先选择适配器模式,完全可控但代码量较大;
  • 追求代码复用与安全平衡:选择继承+重写父类方法抛异常的方案,性价比最高;
  • 绝对避免仅继承不做限制的实现,会导致类极易被误用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:01:07