记一次使用Set为List去重

遇到一个需求,把一个重复的列表去重。我想这还不简单,我立刻想到了使用Set这个集合类,没有具体研究过,但是知道这个就是可以自动去重的。

所以我写了一个方法:

private List<Bean> removeRepeated(List<Bean> beans) {
    Set<Bean> set = new HashSet<>();
    for (Bean bean : beans) {
        set.add(name);
    }
    return new ArrayList<>(set);
}

结果没有达到理想的效果,我转念一想,这是个类的对象,没有重写equals方法,肯定不能就这么成功呀。然后我重写了equals方法

    public boolean equals(@Nullable Object obj) {
        if (obj instanceof Bean)
            return name.equals(((Bean) obj).getName());
        return false;
    }

这样总没问题了吧,结果还是不行,我。。。
我在这个方法里大了一堆Log,结果一个都没显示,好家伙压根就没用这个方法。

我一气之下,直接改用list

    private List<Bean> removeRepeated(List<Bean> beans) {
        List<Bean> set = new ArrayList<>();
        for (Bean bean : beans) {
            if (!set.contains(bean))
                set.add(bean);
        }
        return new ArrayList<>(set);
    }

结果成了,到这里可以收工了,解决了就可以了嘛。
但是问题是为什么使用ArrayList可以,而HashSet 不可以呢?这个问题如鲠在喉。

  • 先看一下为什么可以ArrayList可以。这里我用了contains这个方法做了一个判断,以下是ArrayList的相关源码
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

源码很简单,使用了indexOf方法,在indexOf方法中调用了为被包含类的equals方法,刚好我在类中定义了,所以就成了。
这个理解很容易,那HashSet呢?

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
  • HashSet中内部实现是使用HashMap的,而在HashMap中是使用key的hash值来进行比较存储的,这里HashMap.putVal逻辑有点复杂就不复制了。
  • 因为每个对象的hash值是肯定不一样的,所以对于对象的去重是做不到的,一般用于对基本类型的去重比较好。但是要是非要用这个来做也不是不可以,可以自己重写hashCode方法,保证内容一样的对象hash值一样,这个做法不推荐。
  • 那其他的set的实现类呢?TreeSet需要实现比较器(我又不用排序,用比较器就感觉奇奇怪怪的)ArraySet也用到了hash值,所以我还是用ArrayList吧。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值