笔记之java基础--17

1、Set

Collection有两大体系:

*    A:List
* 元素有序(指的是存储顺序和取出顺序是否一致),可重复
*         B:Set
*                 元素无序,唯一,不可重复
*      
*      通过查看api我们发现,set和Collection功能一致

*      又因为它是接口,所以,找一个实现类HashSet

代码实例可知Set无序且唯一:

注意:1)set遍历方式两种,迭代器和增强for,普通for不可以,因为无序

          2)Iterator迭代器也是泛型类,限制类型后不用,执行it.next()的时候就不用转型

          3)  set保证唯一行,在添加的过程中会自己判断,如果重复则不会添加。

笔记之java基础--17

2、HashSet

      HashSet存储自定义对象,实现了set接口。

     既然set能保证唯一性,那么自定义对象呢,我们认为一个对象,如果成员变量值都相同,则同为一个对象。

    笔记之java基础--17

* 请思考:
 * 为什么字符串可以保证唯一性,而Student对象不能保证唯一性。
 *      A:哪里出问题了
 *      经过简单分析,我们知道了在add方法出问题了。
 *      B:怎么解决
 *      看源码
 *       if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
         {
          ???唯一
         }               
          上面的判断跟对象的hashCode()方法有关      
          在If判断语句中,如果e.hash == hash是false那么不会执行右边,就不会走到equals(k)方法。
          因为对象是new出来的,地址值不一样,hashcode是根据地址值算出来了,故hashcode也不一样。
          即左边永远是false,我们要做的事情就是保证左边是true
          
    分析:
    A:这个判断跟hashcode有关 
    B:这个判断跟equals有关
   
    若想要走equals就保证左边是true,若要保证左边是true就要重写hashcode方法
          
 *      HashSet底层数据结构,哈希表。
 *      哈希表根据哈希算法存储的,存储的就是对象的哈希值。
 *      由于不同对象的哈希值不一样,所以6个元素全部存储成功,所以没有去掉重复值。
 *      而我们向去掉重复值,则么办呢?
 *      首先我们重写了hashCode(),返回值是0,保证了所有的对象的哈希值相同
 *      接着重写了equals()方法,比较对象的成员变量。
 *      重写后,这个时候的存储,哈希表提供了哈希桶结构,这个结构是处理哈希值相同的情况。
 *      哈希桶结构用于处理哈希值相同的情况。
 *      当哈希值相同的情况系,对象会存储在一个桶结构中。
 *      但是,看源码后,我们知道它会走equals()方法。看成员变量值是否相同。
 *      
 *      问题现在是解决了,但是效率又出问题了因为每一个都会调用equal方法,我们需要改进代码,让效率高一些。
 *      如何改变呢?
 *      在hashCode()上想办法,让不可能相同的返回不同的哈希值,这样就不会走equals方法了。
 *      怎么实现?
 *      一般来说,我们在hashCode()方法上不会直接返回一个固定的值,这个值应该是变化的。

 *      这个方法它本质是跟对象的成员变量相关。我们只需要把对象的成员变量值相加即可。

* hashCode();把所有的成员变量值相加,如果是引用类型,用哈希值,如果是基本类型直接用值。
 * Person:
 * String name;
 *          int age;
 *          char sex;
 *          float score;
 *          
 *          public int hashCode()
 *          {
 *          return this.name.hashCode()+this.age +this.sex+this.score

 *          }

代码实现如下,自动生成:

笔记之java基础--17

  3、TreeSet

        TreeSet可以对元素进行排序,同时保证元素唯一。 

         使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator进行排序,具体取决于使用的构造方法。

       1)当对象是String时会按自然顺序对字符串排序:

      笔记之java基础--17

        输出结果每次都是固定的:abcde
        hello
        java

        world

        zon

      由上面结果可知,输出结果有序、唯一、且不重复,这个顺序是自然的顺序首字母有a到z,

      原因是使用了new TreeSet<String>( )这种构造方法。

        2)当TreeSet是Student对象时怎么排序:

           笔记之java基础--17

             报错:Exception in thread "main" java.lang.ClassCastException: 
                     * cn.itcast_02.Student cannot be cast to java.lang.Comparable

                     * Student不能转成Comparable;

             分析:

                    Interface Comparable<T>此接口强行对实现它的每个类的对象进行排序。

                  这种排序称为类的自然排序,类的compareTo方法被称为它的自然比较方法。

                    如果使用TreeSet<Student> ts = new TreeSet<Student>();这种无参构造方法,会对对象进行自然排序。

               这时需要对象所属的类去实现Comparable接口,因为String类实现了Comparable接口,所以可以排序。

           Student类没有实现接口,不知道怎么排序,所以需要Student类去实现Comparable接口,告诉它怎么对对象排序。

笔记之java基础--17

   * TerrSet保证元素排序有两种方式:

 * A:自然排序,让对象所属的类去实现Comparable接口,使用的是无参构造。

       即类要实现Comparable接口,并重写compareTo()方法,TreeSet对象调用add()方法时,会将存入的对象提升为Comparable类型,然后调用对象中的compareTo()方法进行比较,根据比较的返回值进行存储。 正如上面程序,Student类没有实现接口,所以不能提升为Comparable类型,就会报错。

        因为TreeSet底层是二叉树,当compareTo方法返回0时,不存储;当compareTo方法返回正数时,存入二叉树的右子树;当compareTo方法返回负数时,存入二叉树的左子树。如果一个类没有实现Comparable接口就将该类对象存入TreeSet集合,会发生类型转换异常。 

        * TreeSet:底层数据结构是二叉树结构
         * 那么二叉树是如何存储数据的呢?
         * 规则:
         * 第一个添加的数据作为根节点。
 * 从第二个开始
 * 每一个数据从根节点开始比较
 * 如果大了往又放。
 * 如果小了往左放
 * 如果相同,替换
 * 
 * 二叉树的遍历方式有三种
 * 从根节点开始获取数据的规则是按照数据的,左,中,右原则

 * B:比较器接口Comparator,带参构造。

            比较器接口的实现方法:

            1》首先需要按年龄大小排

         笔记之java基础--17

   笔记之java基础--17

   如果需要按姓名长短排呢?

重新写一个MyComparator2 implements Comparator<Student>,然后在主函数中:

TreeSet<Student> ts = new TreeSet<Student>(new MyComparator2());

笔记之java基础--17

另外也可以采用匿名内部类实现:

笔记之java基础--17

这两种方式的比较:

* TerrSet保证元素排序有两种方式:
 * A:自然排序,让对象所属的类去实现Comparable接口,使用的是无参构造。
 * B:比较器接口Comparator,带参构造。
 * 
 * 还是用第二种方法比较好,比如MyComparator()是按年龄排的,MyComparator2()是按姓名长度排的
 * 到时候想让程序按什么排就可以通过
 * TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
 * 或者TreeSet<Student> ts = new TreeSet<Student>(new MyComparator2());
 *实现
 * 开发原则:

 * 对修改关闭,对扩展开放

4、Collections

Collection和Collections的区别?

 * Collection:是Collection集合的顶层接口,定义了Collection集合的共性方法。
 * Collections:是一个类,定义了针对Collection集合操作的功能,有排序,查找,反转等。
 * 
 * Collections的功能:
 * 排序:static  void sort(List<T> list)
 * 二分查找:static <T> int binarySearch(List  list, T key)
 *       返回的是索引
 * 反转:static void reverse(List<?> list)
 * 最大值:max(Collection  coll)
 * 随机置换:shuffle(List<?> list)