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中无重复元素的定义。为此,我来分析一下这个问题。
二.问题的分析
调试该程序,我们得到如下结果。
可以看到,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集合中的元素不重复的特性,我们可以遵循以下原则:
- 避免更改已经加入
Set
集合中的对象的属性值。如果需要更改对象的属性值,可以先从集合中删除该对象,然后更改属性值后再将其重新添加到集合中。 - 在定义用于比较对象是否相等的
equals
和hashCode
方法时,可以考虑使用不可变的属性作为比较依据。这样,即使对象的其他属性发生了变化,也不会影响到对象在Set
集合中的唯一性。 - 如果需要在
Set
集合中存储可变对象,并且需要频繁更改对象的属性值,可以考虑使用其他数据结构,例如List
或Map
,来替代Set
集合。