Java中实现引用相等的Set,首选Collections.newSetFromMap(new IdentityHashMap()),它基于==比较,符合引用唯一性要求;也可用IdentityHashMap手动模拟,或保留Object默认equals/hashCode,但后者易引发业务逻辑冲突。

Java 中的 HashSet 默认不进行引用比较,而是基于 equals() 和 hashCode() 判断对象是否重复。但如果你确实需要引用比较语义(即两个对象只有是同一个实例才视为相等),有几种明确可行的方式。
直接使用 IdentityHashMap 包装的 Set 语义
Java 没有内置的 “IdentityHashSet”,但可以用 IdentityHashMap 模拟:键为对象,值固定为 Boolean.TRUE。它内部使用 == 比较 key,天然支持引用相等性。
- 插入:
identityMap.put(obj, Boolean.TRUE) - 查重:
identityMap.containsKey(obj)返回 true 仅当obj是同一引用 - 遍历元素:
identityMap.keySet()即为“引用去重”的集合视图
自定义包装类 + 不重写 equals/hashCode
如果你控制对象的定义,最简单的方法是完全不重写 equals() 和 hashCode(),保留 Object 的默认实现。
- 此时
equals()等价于==,hashCode()返回基于内存地址的哈希值 - 只要不重写,HashSet 就会按引用判断唯一性
- ⚠️ 注意:一旦其他地方依赖内容相等(如作为 Map 的 key 或参与业务逻辑),这种方式会出错,需谨慎评估场景
用 Collections.newSetFromMap 配合 IdentityHashMap
这是最接近标准 Set 接口的轻量方案:
立即学习“Java免费学习笔记(深入)”;
Set<myobj> identitySet = Collections.newSetFromMap(new IdentityHashMap());</myobj>- 返回的 Set 支持全部标准操作(
add、contains、remove等) - 所有行为都基于
==,无需修改原类,也无需手写包装逻辑
为什么不建议强行改写 equals 为 ==?
有人试图在自定义类中这样写:
public boolean equals(Object o) { return this == o; }
public int hashCode() { return System.identityHashCode(this); }
虽然技术上可行,但存在明显问题:
- 违反
equals的对称性契约(若另一方类未同步改写,比较结果可能不对称) - 与业务语义冲突:比如两个
Person("Alice", 25)实例本应逻辑相等,却因引用不同被当作不同对象 - 后续调试困难,容易被团队误认为是 bug 而非设计选择


















