上面的输出结果可能有点让人觉得意外,从输出的结果可知输出的内容已经重复了(有两个-3),但是因为HashSet把他们添加到了不同的地方,所以HashSet完全可以容纳两个相同的元素。
但是当我们试图删除count为-3的R对象的时候,HsahSet会计算出该对象的hsahCode值,从而找出该对象在集合中保存的位置,然后把此处的对象与count为-3的R对象通过equals()方法进行比较,如果相等就删除该对象-----HashSet只有第三个元素才满足该条件(第一个元素实际上是存的count值为5的R 对象对应的位置,所以第三个元素会被删除)。
因此在修改HashSet集合中的对象时,应该考虑到,修改有可能导致该对象与集合中的其他对象相等,从而导致HashSet无法准确访问该对象。
同样的情况也会发生在TreeSet中,如果向TreeSet中添加一个可变对象后,后面的程序修改了改可变对象的成员变量,这将导致与其他对象的大小顺序发生改变,但是TreeSet不会再次调整他们的顺序,甚至可能导致这两个对象通过compareTo(Object obj)方法比较返回0.下
================《疯狂Java讲义精粹》读书笔记13 ------ Set集合(二)==============
在上一篇笔记中提出了这样一个问题:修改Set中对象的成员变量之后可能与集合中的其他元素相等,这不就与Set集合的规则矛盾了吗?
先考虑HashSet的情况:
import java.util.HashSet;
import java.util.Iterator;classR{intcount;public R(intcount){this.count =count;
}//重写toString()方法
publicString toString(){return "R[count:" + count + "]";
}//重写equals()方法
publicboolean equals(Object obj){if(this ==obj){return true;
}if(obj != null && obj.getClass() == R.class){
R r=(R)obj;if(r.count == this.count){return true;
}
}return false;
}//重写hashCode()方法
public inthashCode(){return this.count;
}
}public classTestHashSet {public static voidmain(String[] args) {
HashSet hs = new HashSet();
hs.add(new R(5));
hs.add(new R(-3));
hs.add(new R(9));
hs.add(new R(-2));//打印集合,这时候集合里面还没有重复的元素
System.out.println(hs);
Iterator it =hs.iterator();
R first=(R)it.next();//为第一个元素的count实例变量赋值
first.count = -3;//再次输出HashSet集合,集合内有重复的元素
System.out.println(hs);//删除count为-3的元素,只被删除了一个元素
hs.remove(new R(-3));
System.out.println(hs);//还是否包含count值为-3的元素//很奇怪的是,会输出false
System.out.println("hs中是否还存在count = -3的元素:" + hs.contains(new R(-3)));//count值为5 的元素不存在了
System.out.println("hs中是否包含count值为5 的元素:" + hs.contains(new R(5)));
}
}
输出的结果是:
[R[count:5], R[count:9], R[count:-3], R[count:-2]]
[R[count:-3], R[count:9], R[count:-3], R[count:-2]]
[R[count:-3], R[count:9], R[count:-2]]
hs中是否还存在count= -3的元素:falsehs中是否包含count值为5 的元素:false
上面的输出结果可能有点让人觉得意外,从输出的结果可知输出的内容已经重复了(有两个-3),但是因为HashSet把他们添加到了不同的地方,所以HashSet完全可以容纳两个相同的元素。
但是当我们试图删除count为-3的R对象的时候,HsahSet会计算出该对象的hsahCode值,从而找出该对象在集合中保存的位置,然后把此处的对象与count为-3的R对象通过equals()方法进行比较,如果相等就删除该对象-----HashSet只有第三个元素才满足该条件(第一个元素实际上是存的count值为5的R 对象对应的位置,所以第三个元素会被删除)。
因此在修改HashSet集合中的对象时,应该考虑到,修改有可能导致该对象与集合中的其他对象相等,从而导致HashSet无法准确访问该对象。
同样的情况也会发生在TreeSet中,如果向TreeSet中添加一个可变对象后,后面的程序修改了改可变对象的成员变量,这将导致与其他对象的大小顺序发生改变,但是TreeSet不会再次调整他们的顺序,甚至可能导致这两个对象通过compareTo(Object obj)方法比较返回0.下面的程序演示了这种情况:
importjava.util.TreeSet;class T implementsComparable{intcount;public T(intcount) {this.count =count;
}publicString toString(){return "T[count:" + count + "]";
}//重写equals方法,根据count来判断是否相等
public booleanequals(Object obj) {if(this ==obj){return true;
}if (obj != null && obj.getClass() == T.class) {
T t=(T)obj;if(t.count == this.count){return true;
}
}return false;
}//重写compareTo()方法,根据count来比较大小
@Overridepublic intcompareTo(Object obj){
T t=(T)obj;return count>t.count?1:
count< t.count?-1:0;
}
}public classTreeSetTest {public static voidmain(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new T(5));
ts.add(new T(-3));
ts.add(new T(9));
ts.add(new T(-2));
System.out.println(ts);
T firs=ts.first();
firs.count= 20;//修改后没有排序
System.out.println(ts);
T last=ts.last();
last.count= -2;//将会看到集合里的元素处于无序状态,且有重复的元素
System.out.println(ts);//删除count=-2的T对象,将会删除失败
System.out.println(ts.remove(new T(-2)));
System.out.println(ts);//查询是否有count=20的T对象
System.out.println("是否存在count=20的T对象:" + ts.contains(new T(20)));
}
}
输出结果:
[T[count:-3], T[count:-2], T[count:5], T[count:9]]
[T[count:20], T[count:-2], T[count:5], T[count:9]]
[T[count:20], T[count:-2], T[count:5], T[count:-2]]false[T[count:20], T[count:-2], T[count:5], T[count:-2]]
是否存在count=20的T对象:false
与HashSet类似如果修改了TreeSet中的可变对象,会很容易出错。