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

Java中HashSet存储ArrayList对象的内部机制?为何示例代码输出为1?

为什么HashSet存储两个内容相同的ArrayList后size是1?

这问题特别典型,我来给你一步步理清楚:

首先得搞懂HashSet的核心判断逻辑

HashSet不会直接存储对象的哈希值,它的去重逻辑依赖两个方法的配合:

  • 第一步:调用对象的hashCode()方法计算哈希值,找到对应的存储桶;
  • 第二步:在对应桶里,用equals()方法和已有的元素逐一比较;
  • 只有当两个对象的hashCode相等,并且equals返回true时,HashSet才会判定这是同一个元素,拒绝重复添加。

再看ArrayList的equals()和hashCode()实现

ArrayList作为Java集合框架的一员,它的这两个方法是基于集合内容实现的,而非对象本身的内存地址:

  • equals():会遍历两个列表的所有元素,逐个用元素的equals()比较,只要元素数量相同、顺序相同、每个对应位置的元素都相等,就返回true;
  • hashCode():根据列表里所有元素的哈希值计算得出,核心逻辑大概是:
    int hashCode = 1;
    for (E e : list) {
        hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
    }
    
    所以只要两个ArrayList的内容完全一致,它们的hashCode值肯定相同。

回到你的代码场景

你的代码里:

  • list1和list2是两个不同的对象(内存地址不同),但它们的内容完全一致:都包含Integer(1)和Integer(2),顺序也一样;
  • 所以list1.equals(list2)返回true,两者的hashCode()值也完全相等;
  • 当你先把list1加入HashSet,再添加list2时,HashSet发现它和已有的list1满足“hashCode相等+equals返回true”的重复判定条件,就不会把list2加入集合,最终set的size就是1。

额外补充:如果想让它们被当成不同元素怎么办?

如果你的业务场景需要把“内容相同但内存地址不同的ArrayList”当成不同元素存入HashSet,那你可以自定义一个继承ArrayList的子类,重写equals()和hashCode(),让它们基于对象的身份(比如用System.identityHashCode(this))来计算,举个例子:

class IdentityArrayList<E> extends ArrayList<E> {
    @Override
    public boolean equals(Object o) {
        return this == o;
    }

    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }
}

用这个子类创建list1和list2,再存入HashSet,size就会是2了——不过这种做法很少见,一般只有特殊业务需求才会这么做。

内容的提问来源于stack exchange,提问作者Ganesh Chowdhary Sadanala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 14:42:52