java修改Set中的元素

java修改Set中的元素

一.问题的提出

在java中,有以下代码:

public class Test{
    public static void main(String[] args) {
        Set<Stu> set = new HashSet<>();
        Stu s1 = new Stu(1);
        Stu s2 = new Stu(2);
        set.add(s1);
        set.add(s2);
        s1.id = 2;

        System.out.println(set.size());
        System.out.println(s1.equals(s2));
        System.out.println(s1.hashCode() == s2.hashCode());
    }
}

class Stu{
    public int id;
    public Stu(int id){
        this.id = id;
    }

    @Override
    public boolean equals(Object s){
        if(s instanceof Stu){
            Stu temp = (Stu) s;
            if(temp.id == this.id){
                return true;
            }

        return false;
        }
        
        return false;
    }
    
    @Override
    public int hashCode(){
        return Objects.hash(id);
    }

}

运行该代码,会发现输出

2
true
true

意思是在Set中出现两个相同的元素(equals比较时相同,hashCode也相同),这不符合Set中无重复元素的定义。为此,我来分析一下这个问题。

二.问题的分析

调试该程序,我们得到如下结果。

img

可以看到,s1和s2虽然hashCode相同,equals方法也会返回true,但还是存在两个不同的地址中,只是通过修改equals和hashCode方法,让它们在逻辑上相同了。这时,如果我们再重新建立一下set,如下所示:

public static void main(String[] args) {
    Set<Stu> set = new HashSet<>();
    Stu s1 = new Stu(1);
    Stu s2 = new Stu(2);
    set.add(s1);
    set.add(s2);
    s1.id = 2;

    System.out.println(set.size());
    System.out.println(s1.equals(s2));
    System.out.println(s1.hashCode() == s2.hashCode());

    set = set.stream().collect(Collectors.toSet());
    System.out.println(set.size());
}

这时,我们发现set的大小又变成了1。

三.问题结论

通过上面的小实验,我们可以看到,java是在Set建立和往其中加元素时保证的Set的中元素不重复,但如果元素已经放入集合中,再通过指针修改其中的元素,Set是无法保证其中元素被修改后仍然不重复的。

为了维护Set集合中的元素不重复的特性,我们可以遵循以下原则:

  1. 避免更改已经加入 Set 集合中的对象的属性值。如果需要更改对象的属性值,可以先从集合中删除该对象,然后更改属性值后再将其重新添加到集合中。
  2. 在定义用于比较对象是否相等的 equalshashCode 方法时,可以考虑使用不可变的属性作为比较依据。这样,即使对象的其他属性发生了变化,也不会影响到对象在 Set 集合中的唯一性。
  3. 如果需要在 Set 集合中存储可变对象,并且需要频繁更改对象的属性值,可以考虑使用其他数据结构,例如 ListMap,来替代 Set 集合。
posted @ 2023-06-14 15:09  tryingWorm  阅读(301)  评论(0编辑  收藏  举报