Day17 --集合框架 Set集合

来源:互联网 发布:陕西广电网络是国企嘛 编辑:程序博客网 时间:2024/05/29 19:13
 a.
    Set
        概述
            * util包下,是双列集合Collection下的一个子接口
            * 包含:HashSet    linkedHashSet    TreeSet
            * set集合中的元素不可重复,无索引,存取无序(存和取的顺序不一致)
            * 遍历集合的方式不能使用size()和get(int index),因为set是无索引的,用增强for来遍历元素
            * 只要能使用迭代器来遍历集合元素对象的,同样能用增强for来遍历
        使用
            * 代码实现
                
b.
     HashSet存储自定义对象
        * 存储自定义对象,来保证元素的唯一性
        * 前提Bean对象必须重写 hasCode方法和equals方法
            * 当hasCode的值一样时,比较equals方法,当hasCode值不同时,就没有必要比较equals方法
            * 所以尽量让hasCode的值不同,从而减少对equals方法的调用而直接判断元素对象是否重复
            * 所以要对hasCode方法进行优化:
                * 最终版:采用 自动生成的 hasCode和equals方法。快捷键:Shift+Alt+s+h
                * 之所以自带的hasCode方法之那么复杂,就是为了少调用equals方法,从而提高代码的运行效率。
            * 哈希表确定元素是否相同
                * 1.判断的是两个元素的哈希值是否相同。
                    * 如果相同,再判断两个对象的内容是否相同。
                  2.判断哈希值相同,其实就是判断对象的hashCode方法,判断内容相同,用的是equals方法、
            P.S.
                * 如果哈希值不同,就无需判断equals方法。     

    
    HashSet保证元素唯一性的原理
        * 1)我们使用set集合存储元素,就是为了防止重复元素的存入。 如果在存储的时候逐个比较equals方法,这样导致效率降低。而哈希算法提高了去重复元素的效率。降低了对equals方法次数的调用。 --因为当hasCode值不同时,该元素已经被判定为不是重复,从而就没有必要比较equals方法了。
            * 当HashSet调用add()方法存入元素对象的时候,会先去调用hasCode()方法得到一个哈希值,然后在set集合中去找是否有重复哈希值对象的存在:
                * 如果没有哈希值相同的对象:就将该元素对象存储到集合中去。
                * 如果有哈希值相同的对象:就和哈希值相同的对象逐个比较equals方法。如果比较的结果为false,就表示在集合中没有该元素对象,就可以存入。如果比较的结果为true,就表示集合中已经有该元素的存在,就不能在存入集合中了。
                
        * 2)将自定义类的对象存入HashSet,去重复:
            * 类中必须重写hasCode 和 equals 方法。--快捷键:Shift+Alt+s+h
            * hasCode(): 属性相同的对象返回值必须相同。属性不同的返回值尽量不同(提高效率) --因为hasCode值不同,是否是重复元素就已经确定,就无需比较equals方法,从而达到降低了对equals方法的调用。
            * equals(): 属性相同返回true,表示集合中有该元素了,就不存。属性不同就返回false, 表示集合中没有该元素对象,可以存入。


c.
    LinkedHashSet
        概述
            * util包下,是一个类。
            * LinkedHashSet中的Linked保证:底层是:链表结构实现,是set集合中唯一一个保证怎么存怎么取的集合对象,因为是HashSet的子类对象,所以同样保证了元素的唯一性。
            * LinkedHashSet 底层链表结构实现,是set集合中唯一一个保证怎么存怎么取的集合对象,又因为是HashtSet的子类对象,所以保证了集合对象的唯一性。
        使用
            * 代码实现
            * HashSet比LinkedHashSet的效率要高,因为它不保证怎么存怎么取,所以速度要快。
        案例
            * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。
            * 使用Scanner从键盘读取一行输入,去掉其中重复字符
            * 将集合中的重复元素去掉

d.
    TreeSet
        概述
            * util包下,是一个类
            * 基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序Comparable对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。    
            * 底层二叉树实现,可对元素进行自动排序,同样保证元素的唯一性。
            * TreeSet判断元素唯一性的方式:是根据自定义Bean对象实现comparable接口,重写compareTo()比较方法返回结果是否为0,如果是0,就是相同元素,不存。
            
    TreeSet存储自定义对象
        概述
            * 当TreeSet存储自定义Bean对象时,必须要重写compareTo(T o)方法,只能重写了该方法才能进行遍历输出该集合,但前提是,必须自定义对象类必须实现Comparable<T>接口后重写该方法。
            * 重写compareTo方法后,根据返回值的不同,遍历的集合的结果也有所不同:
                * 当compareTo返回值为 0   时 : 遍历集合只有一个元素对象。
                * 当compareTo返回值为 正数 时:  遍历集合会怎么存怎么取。
                * 当compareTo返回值为 负数 时:  遍历集合会将存储的元素倒序。
                    * 为什么是这种情况?分析原因:
                        * TreeSet底层:二叉树实现:两个叉
                            * 较小元素存储在左边(负数),较大元素存储在右边(正数),相等就不存入(0),其实说的就是compareTo方法,在TreeSet集合中如何存储元素取决于每次要看compareTo方法的返回值来决定的。

                            * 但是又存在另一种情况:age相等,而name不等的该怎么办?
                                * 代码: 
                                    * age是比较的主要条件,当age不同时,就无需比较name
                                    * name是比较的次要条件。
                                    * @Override
                                        public int compareTo(Person o) {
                                            int num = this.age - o.age; 
                                            return (num == 0)?  this.name.compareTo(o.name): num; 
                                            
【自然排序的compare方法 和 比较器的compareTo方法 类似于hashcode和equals的比较顺序,都是先比较第一个方法,如果第一个方法条件不成立,就比较第二个方法,如果第一个方法条件成立,就无需比较第二个方法。提高了代码的运行效率】
【当自然排序和比较器排序都存在时,系统会优先以 比较器排序为准。】

TreeSet存储自定义对象并遍历练习1
        * 案例演示
            * TreeSet存储自定义对象并遍历练习1(按照姓名排序)
        * 关键代码    
        @Override
            public int compareTo(Student o) {
                int num = this.name.compareTo(o.name);
                return num==0? this.age -o.age : num;
            }


TreeSet存储自定义对象并遍历练习2
        * 案例演示
            * TreeSet存储自定义对象并遍历练习2(按照姓名的长度排序)
        * 关键代码
            *     @Override
                public int compareTo(Animal o) {
                    int length = this.name.length() - o.name.length(); //name长度 为主要条件,但是name长度一样就比较name内容。
                    int num = length == 0 ? this.name.compareTo(o.name) : length; //name内容为次要条件,当nema长度和name内容也相同的时候,再比较age
                    return num == 0 ? this.age - o.age : num; //age也为次要条件
                }


TreeSet保证元素唯一和比较器排序的原理及代码实现
        * 案例演示
             * TreeSet保证元素唯一和比较器排序的原理及代码实现
        * 关键代码
            * 创建一个类实现Comparator<T>接口。
            // 比较器排序
            class ComparaLen implements Comparator<String>{
            
                @Override
                public int compare(String o1, String o2) {
                    int length = o1.length() - o2.length();  //字符串的长度 length是主要的比较条件
                    return length == 0 ? o1.compareTo(o2) : length; //  字符串的内容(字典顺序排序)是次要条件
                }


TreeSet原理
    概述
        * TreeSet是用做排序的,可以指定一个顺序,元素对象存入集合中会按照指定的顺序进行排列。
    排序方式有两种:
        * 方式一:自然排序[Comparable]
            * 首先 自定义Bean类或普通类 实现Comparable<Animal>接口,重写comparaTo(Animal an)方法。
            * TreeSet类的add()方法中会将存入的元素对象提升为Comparable类型。
            * 调用普通类实现接口后重写comparaTo(Animal an)方法和集合中的元素对象进行依次比较。
            * 根据comparaTo()方法返回值的结果进行存储。
            
        * 方式二:比较器排序[Comparator]
            * 首先 创建TreeSet的时候可以指定一个自定义类来实现comparator接口并重写compare(String s1, String s2)方法。
            * 如果传入Comparator的子类对象,那么TreeSet就会按照比较器中的比较顺序进行排序。
            * add()方法内部会自动调用Comparator接口中的compare()方法进行排序。
            * 调用的对象是compare方法的第一个参数s1, 集合中的对象是compare方法中的第二个参数。    
    两种方式的比较:
        * TreeSet构造函数什么都不传入,默认按照类中的Comparable的顺序,如果没有就会出现:ClassCastException异常。
        * TreeSet构造函数如果传入Comparator,那就会有限按照Comparator 比较器排序的方式进行排序。
        * 如果自定义类实现了Comparable接口,并且TreeSet的构造函数也传入了比较器对象,那么就以比较器的比较规则为准。        

    
练习题    
 需求:在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
 需求:从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
 需求:程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印.
 需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。



双列集合顶层接口:Conllection,底下有两个子接口:List和set
    List 存取有序,有索引,可重复。
        * ArrayList
            * 底层数组结构实现,线程不安全,不同步,所以执行效率高。因为有索引,所以查询快,修改快,增删慢。
        * Vector
            * 底层数组结构实现,线程安全,同步,所以执行效率低。查询快,已经被ArrayList给替代。
        * LinkedList
            * 底层链表结构实现,线程不安全,不同步,所以执行效率高。因为是链表,所以增删快,查询修改慢。
        
    Set 存取无序,无索引,不可重复
        *HashSet
            * 底层哈希算法。线程不安全的,不同步。如果想保证自定义对象的元素的唯一性,那么必须在Bean类中 重写hashCode方法和equals方法。推荐 快捷键:shift+alt+s+h即可。
        
        *LinkedHashSet 
            * 底层链表结构。是Set集合中唯一的一个怎么存怎么取的集合,又因为是Hashset的子类对象,同样保证了元素的唯一性。
        
        *TreeSet:用于排序。
            * 底层二叉树结构,线程不安全的,不同步。
            * 排序方式有两种:
                * 自然排序
                    * 自定义Bean类实现comparable(Person)接口,并且重写compareto(Person p)方法。
                    * TreeSet构造函数无参数。
                * 选择排序
                    * TreeSet构造函数传入Comparator对象,并且使用匿名内部类的方式重写compare(String s1, String s2)方法。
                    
                TreeSet:可以对元素进行排序,唯一
                        重点掌握及记忆的两个内容:
                            A:排序规则
                                前 - 后   升序
                                后 - 前   降序
                
                            B:分析清楚主要条件和次要条件。



双列集合的遍历方式有哪些?
    分为List集合和Set集合。
List
    1)将集合转数组,toArray()后,用增强for遍历集合或普通for;
    2)普通for,配合size()方法和get(int index)方法使用;
    3)使用普通迭代器Iterator,只要可以使用Iterator的类都可以使用,配合hasNext()方法和Next()方法。
    4)使用List中特有的ListIterator迭代器来遍历。
    5)Vector可以使用自己特有的Enumeration的hasMoreElements()方法和nextElement()方法。
    6)使用增强for 直接遍历集合。
Set
    1)使用普通迭代器Iterator,只要可以使用Iterator的类都可以使用,配合hasNext()方法和Next()方法
    2)增强for



普通for循环,迭代器,增强for循环是否可以在遍历的过程中删除?
普通for循环 可以。不过 要索引--;
迭代器 
    * 普通迭代器:
        * 可以。不过要使用迭代器自己的remove()方法删除元素。
    * List特有的迭代器:ListIterator
        * 可以。不过要使用迭代器自己的remove()方法删除元素。 
增强for循环
        * 可以。list集合和set集合都可以用。
原创粉丝点击