《疯狂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中的可变对象,会很容易出错。

 

posted @ 2013-03-11 20:38  Cocoon  阅读(340)  评论(0编辑  收藏  举报