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

  • 相关阅读:
    Django源码解析(1):启动程序
    python之importlib模块
    Django中间件:CsrfViewMiddleware
    Django的admin组件
    Linux学习之CentOS--CentOS6.4下Mysql数据库的安装与配置【转】
    C#读取Xml【转】
    在eclipse导入项目的步骤【转】
    Spring学习(一)——Spring中的依赖注入简介【转】
    Spring学习(二)——Spring中的AOP的初步理解[转]
    Spring之AOP
  • 原文地址:https://www.cnblogs.com/CocoonFan/p/2954608.html
Copyright © 2020-2023  润新知