黑马程序员技术交流社区

标题: 分享一下Set集合笔记+心得 [打印本页]

作者: 呆呆怪兽    时间: 2015-7-25 22:20
标题: 分享一下Set集合笔记+心得
Set:    元素顺序无序,唯一。
    HashSet        元素无序,并不保证顺序永恒不变,因为是根据对象的哈希值进行排序,相对底层哈希值可能是有顺序可以找,但是对于我们来说元素的哈希值是不固定的也是未知的,所以导致集合内元素是无序存储。
    TreeSet
        可以对元素进行排序,并且保证集合内元素唯一。可以排序是因为底层结构是二叉树,二叉树可以根据树节点进行存储和取出。
----------------------------------------------------------------------------------------------
HashSet:    HashSet底层是哈希表,因为无序,所以我们对HashSet需要掌握的就是去重元素。
----------------------------------------------------------------------------------------------
HashSet去重元素:
    这里只总结需要自定义规则去重元素。一般是针对引用类型对象
    eg:学生对象(姓名年龄相同即为同一元素)
------------------------------------

    为什么要自定义规则?
        因为学生对象在每次创建的时候都会生成新对象,这些对象在内存里的哈希值肯定不会相同,所以java提供给我们的比较哈希值得方法就不能满足我们的需求,因此我们要根据自己的规则来定义哪些元素是相同元素。
------------------------------------

    怎么实现?
        因为哈希表比较相同元素依赖的是hashCode()方法和equals()方法,因此我们只需要重写这两个方法即可。
hashCode底层代码如下(仅判断部分):
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
通过代码可以看出底层的比较是先比较哈希值,再比较equals,如果前面就已经相同,就不会调用equals方法,所以我们依次是先重写hashCode()和equals()。
------------------------------------

    怎么重写?
        先判断hashCode是否相同
            相同----继续走equals方法,根据返回值决定元素是否重复。(true:重复,不添加到集合;false 不重复,添加元素到集合)
            不同----直接添加到集合
        重写方法:
       【重写 hashCode()】:
            把对象所有的变量值相加即可。基本类型加值,引用类型加它的hashCode值。
        代码实现:
               public int hashCode(){
                    return this.name.hashCode()*13 + this.age*12;//后面乘以一个数是为了防止出现对应的值分别是1、2 -----2、1 这类情况导致的误判hashCode值相同。
                }
        【重写equals()】:
            三步:1、判断是不是同一个对象,如果是,直接返回true
                        2、判断是不是对应的类型(这里是判断是不是Student类型)
                        3、接收的参数强转成对应类型,然后添加比较规则。
            代码实现:
            public boolean equals (Object obj){
                //1、判断是不是同一个对象
                if(this == obj){
                    return true;
                }
                // 2、判断是不是对应的类型
                if(!(obj instanceof Student)){    //如果obj不是Student类型
                    return false;
                //这步在调用集合的add();方法时候其实并没有什么意义,这步主要是为了防止其他方法调用equals的时候程序出问题做的优化,例如System.out.prinln(new Student("隔壁老王").equals(new Animal("拉拉")));
                }
                Student s = (Student)obj;//把接收进来的对象转成Student类型就可以调用它的参数了。
                return this.name.equals(s.name) && this.age == s.age;//判断姓名和年龄都相同就为相同元素。
            }
------------------------------------

上面扯这么多,其实如果不明白,那最起码要明白在什么情况下需要重写hashCode()和equals()方法,然后用eclipse的soure里面自动生成就可以了,这是最次要求了。
----------------------------------------------------------------------------------------------

TreeSet    TreeSet的底层是二叉树,所以它和HashSet的区别就是在保证元素唯一的时候还可以进行简单的排序。
排序方式有两种,
    1、自然排序(使元素具有比较性):
        这个调用的是TreeSet的无参构造,但是实体类需要
        A、继承Comparable<E>接口
        B、重写conpareTo(Object o);方法
        代码实现:
            public class Student implements Comparable<Student>{
                 @Override
                 public int compareTo(Student s) {
                      int num1 = this.getAge() - s.getAge() ;//s放前面是从大到小排,s放后面是从小到大排
                      int num2 = (num1 == 0) ? this.getName().compareTo(s.getName()) : num1;
                      return num2;
                 }
            }
    2、比较器排序(使集合具有比较性,这也是两个比较器的不同之处):
         这里使用的是TreeSet的带参构造,里面传了一个Comparator接口的对象

        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
           @Override
           public int compare(Student s1, Student s2) {
                                        int num1 = this.getAge() - s.getAge() ;//s放前面是从大到小排,s放后面是从小到大排
                      int num2 = (num1 == 0) ? this.getName().compareTo(s.getName()) : num1;
                      return num2;

               }
          });


作者: 木森    时间: 2015-7-25 23:06
厉害 棒棒的 加油 很详细




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2