如何限制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
相关产品推荐
相关产品推荐

