利用set去重原理实现对象列表去重

set去重原理

大家都知道,set()自带天然去重,例如

	Set<String> set = new HashSet<String>();
	
	set.add("aaa");
	set.add("bbb");
	set.add("aaa");
	set.add("ccc");
		
	System.out.println(set);
 它的输出结果为:[aaa, ccc, bbb]

可以看到:1.去重了;2.输出无序

那么,set()是如何去重的呢

自定义一个类

为了贴合实际的开发需求,我们常需要自定义数据结构。拿通用示例 Student 来说。

class Student{

    private String name;
    private int age;
    private int sid;
    
    public Student(String name, int age, int sid){
        this.name = name;
        this.age = age;
        this.sid = sid;
    }
}

现在,我们实例两个 Student 对象,分别是 stu1 和 stu2,其名字 name,年龄 age,学号 sid 相同。现实生活中,可以认为这两个学生是同一人。

测试

public static void main(String[] args) {
        Set<Student> set = new HashSet<Student>();

        Student stu1 = new Student("jiang", 20, 121);
        Student stu2 = new Student("jiang", 20, 122);

        set.add(stu1);
        set.add(stu2);
        System.out.println(stu1 == stu2);
        System.out.println(set);
    }

输出

false
[Student@1218025c, Student@548c4f57]

可见,对于new出来的两个对象 stu1 和 stu2 set并没有做去重

发现

跟踪add()发现

/**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

点进去看到

    private transient HashMap<E,Object> map;
 
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
 
    /**
     * 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<>();
    }

1.现在我们看到了,map是HashMap类型,Hash类型是散列的,所以无序。

2.因为new了一个对象名为PERSENT的Object对象。以传入的e作为key值,PERSENT作为value来存储到map中,如果key值相同,将会覆盖,这就是set为什么能去重的原因(key相同会覆盖)。

改造

我们在 Student 类中重写 equals方法 和 hashCode方法

@Override
    public boolean equals(Object obj) {

        Student tmp = (Student)obj;
        if(tmp.getAge() == this.age && tmp.getName() == this.name && tmp.getName() == this.name){
            return true;
        }else{
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.getName().hashCode()+this.age;
    }

然后重新打印输出set

[Student@606f04f]

我们发现,它只有一个了,完成了去重操作

这两个方法少些一个都不行

去重原理

经过前面一步步推导,我们得到了set()去重的原理

  1. set() 函数中会先调用对象的 hashCode() 方法,获取 hash 结果;
  2. 如果 hash 结果相同,用比较操作符 == (也就是调用函数 equals())判断二者的值是否相等;
  3. 如果都相等,去重;否则,set() 认为二者不同,两个都保留到结果中。
  • 2
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值