《疯狂Java讲义精粹》读书笔记13 ------ Set集合(二)
================《疯狂Java讲义精粹》读书笔记13 ------ Set集合(二)==============
在上一篇笔记中提出了这样一个问题:修改Set中对象的成员变量之后可能与集合中的其他元素相等,这不就与Set集合的规则矛盾了吗?
先考虑HashSet的情况:
import java.util.HashSet;
import java.util.Iterator;
class R{
int count;
public R(int count){
this.count = count;
}
//重写toString()方法
public String toString(){
return "R[count:" + count + "]";
}
//重写equals()方法
public boolean 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 int hashCode(){
return this.count;
}
}
public class TestHashSet {
public static void main(String[] args) {
HashSet<R> hs = new HashSet<R>();
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<R> 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的元素:false
hs中是否包含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.下面的程序演示了这种情况:
import java.util.TreeSet;
class T implements Comparable{
int count;
public T(int count) {
this.count = count;
}
public String toString(){
return "T[count:" + count + "]";
}
//重写equals方法,根据count来判断是否相等
public boolean equals(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来比较大小
@Override
public int compareTo(Object obj){
T t = (T)obj;
return count>t.count?1:
count < t.count?-1:0;
}
}
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<T> ts = new TreeSet<T>();
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中的可变对象,会很容易出错。