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

是否存在基于对象引用判定重复元素的Java集合实现?

满足需求的集合实现:基于对象身份的Set

你想要的是基于对象引用(而非值相等)判断重复的集合,Java标准库虽然没有直接提供名为IdentityHashSet的类,但可以通过现有API轻松构造出符合要求的实现,完全不需要自己从零开始写。

为什么HashSet不符合你的需求?

HashSet的重复判断依赖元素的equals()和hashCode()方法。对于Rectangle来说,它的equals()是比较矩形的几何属性(x、y坐标和宽高),所以初始状态下的r1和r2虽然是不同引用,但因为值相等,HashSet会认为它们是同一个元素,这就是你看到初始add(r2)返回false的原因。

解决方案:用Collections.newSetFromMap + IdentityHashMap

IdentityHashMap是Java提供的一个特殊Map实现,它用**对象引用相等(==)**来判断键的唯一性,而不是依赖equals()。我们可以用Collections.newSetFromMap()方法,把IdentityHashMap包装成一个Set,这个Set就会完全按照对象引用来判断重复。

修改后的代码示例

import java.awt.Rectangle;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Set;

public class SetTest {
    public static void main(String[] args) {
        Rectangle r1 = new Rectangle();
        Rectangle r2 = new Rectangle();
        // 构造基于身份的Set
        Set<Rectangle> set = Collections.newSetFromMap(new IdentityHashMap<>());
        
        System.out.println("Add r1 : " + set.add(r1));
        System.out.println("Contains r2 : " + set.contains(r2));
        System.out.println("Add r2 : " + set.add(r2));
        System.out.println();
        
        r2.grow(100,100);
        System.out.println("Grow r2");
        System.out.println("Contains r2 : " + set.contains(r2));
        System.out.println("Add r2 : " + set.add(r2));
        System.out.println("Contains r2 : " + set.contains(r2));
        System.out.println();
        
        r2.grow(100,100);
        System.out.println("Grow r2");
        System.out.println("Contains r2 : " + set.contains(r2));
    }
}

运行结果(完全符合你的期望)

Add r1 : true
Contains r2 : false
Add r2 : true

Grow r2
Contains r2 : true
Add r2 : false
Contains r2 : true

Grow r2
Contains r2 : true

额外说明

这个实现的核心特性:

  • 仅当两个对象是同一个引用(obj1 == obj2)时,才会被视为重复元素
  • 即使对象的内部状态(比如Rectangle的大小)改变,只要引用不变,集合依然能正确识别它(因为IdentityHashMap使用的是System.identityHashCode(),这个值在对象生命周期内不会改变)

如果需要更直观的类名,你也可以封装一个自己的IdentityHashSet:

import java.util.AbstractSet;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Set;

public class IdentityHashSet<E> extends AbstractSet<E> {
    private final Set<E> delegateSet;

    public IdentityHashSet() {
        delegateSet = Collections.newSetFromMap(new IdentityHashMap<>());
    }

    @Override
    public boolean add(E e) {
        return delegateSet.add(e);
    }

    @Override
    public boolean contains(Object o) {
        return delegateSet.contains(o);
    }

    @Override
    public Iterator<E> iterator() {
        return delegateSet.iterator();
    }

    @Override
    public int size() {
        return delegateSet.size();
    }

    // 根据需求重写其他Set方法即可
}

这样你就可以直接使用IdentityHashSet<Rectangle> set = new IdentityHashSet<>();,和普通Set的使用方式完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:52:34