浅谈List去重

本文详细介绍了使用Set进行List数据去重的两种常见方法:针对基本数据类型和对象类型的去重策略。对于对象类型,文章深入解析了如何通过重写equals()和hashCode()方法来实现有效去重,并阐述了其背后的HashMap工作原理。

List数据去重在开发中是十分常见的场景,下面为大家介绍一个简单的方法:利用Set去重,但根据存储元素的不同,可以分为以下两类:

1. List中存储的是基本数据类型

下面看一段示例代码:

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d", "a", "b"));
        System.out.println(list);// 输出结果:[a, b, c, d, a, b]
        Set<String> set = new HashSet<>(list);
        List<String> newList = new ArrayList<>(set);
        System.out.println(newList);// 输出结果:[a, b, c, d]
    }
}

2. List中存储的是对象类型

示例代码:

public class Test {
    public static void main(String[] args) {
        List<People> peopleList = new ArrayList<>();
        peopleList.add(new People("Joey", "001"));
        peopleList.add(new People("Joey", "001"));
        peopleList.add(new People("Johnny", "002"));
        peopleList.add(new People("Route", "003"));
        peopleList.add(new People("Vans", "004"));
        Set<People> peopleSet = new HashSet<>(peopleList);
        System.out.println(peopleSet);
    }
}

public class People {

    private String name;
    private String addrNum;

    // 省略无参、有参构造器,get、set方法,toString方法

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        People people = (People) obj;
        return Objects.equals(name, people.name)
                && Objects.equals(addrNum, people.addrNum);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, addrNum);
    }
}

如果List中存储的是对象类型,要想利用Set去重,就必须重写存储对象的equals()和hashCode()方法,为什么呢?

原因其实很简单,如下所示,HashSet的实现其实是HashMap,而HashMap中,通过key区分不同元素,key的比较顺序第一步就是计算对象的hashCode,看是否存在,第二步查找对应hashCode位置的对象是否与当前对象相等。这就需要用到hashCode()与equals()方法,equals()方法的默认实现是 ==,对于对象而言,比较的是内存中的地址。上述示例中,其实我们想要的效果是name与addrNum相等即视为同一个对象,但new的操作在堆中都是开辟新的内存空间,故两个对象的地址不一致,所以,我们必须覆写这两个方法

/**
 * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
 * default initial capacity (16) and load factor (0.75).
 */
public HashSet() {
    map = new HashMap<>();
}

/**
 * Object类中equlas的默认实现
 */
public boolean equals(Object obj) {
    return (this == obj);
}

是不是非常简单,但可能有朋友会问,String并不属于基本数据类型,为什么也可以直接利用Set去重?其实,String类也重写了equals()和hashCode()方法,感兴趣的朋友可以去查看相关源码

总结:

利用HashSet去重,本质是利用了HashMap去重原理,Map/Set的key为自定义对象时,必须重写hashCode和equals

遵循如下规则(来自阿里巴巴Java开发手册):

1. 只要重写equals,就必须重写hashCode

2. 因为set存储的是不重复的对象,依据hashCode和equals进行判断,所以set存储的对象必须重写这两个方法

3. 如果自定义对象作为Map的键,那么必须重写hashCode和equals

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值