day03 List Set 今日内容 
数据结构 
集合 
        List集合 
        Set集合 
Collections集合工具类 
 数据结构 
数据结构: 就是数据的存储方式 
        不同的数据结构代表了不同的存储方式 
        不同的数据结构中, 会有不同的存入, 取出, 查找的方式和效率, 数据的存放方式也不同 
         
        如薯片, 可以用长纸筒装, 也可以用塑料包装袋装, 在两种容器中的存储方式就不同, 放入和取出的方式也不一样 栈知识点: 
栈结构存入和取出数据的顺序有什么特点 
栈结构适用于什么场景 
总结: 
栈: 
    ^  | 
    |  v 
|             |  出入口在同一端 
| +---------+ | 
| |    3    | | 
| +---------+ | 
| +---------+ | 
| |    2    | |   栈 
| +---------+ | 
| +---------+ | 
| |    1    | | 
| +---------+ | 
+-------------+ 
栈的特点:  
        先进后出 (FILO, First In Last Out) 
        入口和出口在同一侧 
         
入栈(压栈): 将元素存入栈 
出栈(弹栈): 从栈中取出元素栈的适用场景: 
        栈内存 (main方法先进栈调用, main方法中的其他方法都调用完毕后, main才能出栈) 
        反转内容 (车尾变车头, 进去再出来就反转了) 
补充: 队列知识点: 
队列结构存入和取出数据的顺序有什么特点 
队列结构适用于什么场景 
总结: 
队列:入口                                                  出口 
   ----------------------------------------------- 
        +---------+ +---------+ +---------+  
---->       |   3   | |   2   | |   1   |  ----> 
        +---------+ +---------+ +---------+ 
   ----------------------------------------------- 
队列的特点: 
        先进先出 (FIFO, First In First Out) 
    入口和出口在两端 
     
队列的适用场景: 
        秒杀, 抢购 
        在线售票 
        处理高并发场景补充: 数组知识点: 
数组结构增删和查询数据有什么特点 
数组结构适用于什么场景 
总结: 
数组:  
        0x01  0x02  0x03  0x04  0x05 
        +-----+-----+-----+-----+-----+ 
        | "a" | "b" | "c" | "d" | "e" | 
        +-----+-----+-----+-----+-----+ 
                0   1                   2   3           4 
         
数组的特点: 
        查询快: 通过 (第一个元素地址值 + 索引) 可以快速计算出该索引元素的地址值 
        增删慢: 增加一个元素, 要创建长度+1的新数组, 然后将原数组元素复制到新数组, 然后存入新元素; 删除类似 
         
        // 添加元素 
        +-----+-----+-----+-----+-----+ 
        | "a" | "b" | "c" | "d" | "e" |   如果要添加元素"f" 
        +-----+-----+-----+-----+-----+ 
         
        +-----+-----+-----+-----+-----+-----+ 
        | "a" | "b" | "c" | "d" | "e" | "f" |  创建一个新数组, 将原数组元素复制进去, 然后存入新元素 
        +-----+-----+-----+-----+-----+-----+ 
         
数组的适用场景: 
        查询多, 增删少的数据存储场景   国内城市补充: 链表知识点: 
链表结构增删和查询数据有什么特点 
链表由什么组成 
什么是单向链表 
什么是双向链表 
链表结构适用于什么场景 
总结: 
链表: 链表由多个 节点(Node / Entry) 组成 
        +-----+-----+-----+    +-----+-----+ 
        |     |     |     |    |数据  |     | 
        +-----+-----+-----+    +-----+-----+     
单向链表: 每个节点存储 数据 和 下一个节点的地址值        链表 = 0x11;        0x11              0x44              0x88 
        +-----+-----+     +-----+-----+     +-----+-----+ 
        | "a" | 0x44| --> | "b" | 0x88| --> | "c" | null| 
        +-----+-----+     +-----+-----+     +-----+-----+ 
      数据  下一个        数据  下一个       数据  下一个 
双向链表: 每个节点存储 数据, 上一个节点地址值 和 下一个节点地址值  
        0x11                    0x44                      0x88 
        +-----+-----+-----+      +-----+-----+-----+      +-----+-----+-----+ 
        |null | "a" | 0x44| <--> |0x11 | "b" | 0x88| <--> |0x44 | "c" | null| 
        +-----+-----+-----+      +-----+-----+-----+      +-----+-----+-----+ 
     上一个  数据  下一个        上一个  数据  下一个        上一个  数据  下一个 
链表的特点: 
        查询慢: 要找到其中某个节点, 只能从第一个节点一个一个向后寻找 
        增删快: 只需要修改保存的下一个节点的地址值, 就可以快速完成增删 
         
        // 删除结点 
        +---+           +---+   +---+ 
        | 1 |----| 2 |----| 3 | 
        +---+           +---+   +---+ 
        +---+                      +---+ 
        | 1 |-------------| 3 | 
        +---+                        +---+ 
                            +---+ 
                            | 2 | 
                            +---+ 
         
链表的适用场景: 
        查询少, 增删多的场景 
        链表可以实现栈和队列的结构, 因为栈和队列增删频繁 
补充: 
代码中链表节点的实现:// 单向链表的节点 
class Node<T> { 
        T data;       // 存储的数据 
        Node next;    // 下一个节点的地址值 
}// 双向链表的节点 
class Node<T> { 
        T data;       // 存储的数据 
        Node before;  // 上一个节点的地址值 
        Node after;   // 下一个节点的地址值 
} 
 红黑树知识点: 
红黑树结构有什么特点 
红黑树结构适用于什么场景 
总结: 
红黑树: 是一种 平衡 二叉 查找 树 
        平衡: 左子节点和右子节点数量相等 
        二叉: 每个节点最多有2个子节点 
        查找: 节点存储的元素是按照大小顺序存储的 
        特点: 
                元素存储过程中就完成了大小排序 
                查询比链表快, 增删比数组快 (数组和链表的折中)红黑树的适用场景: 
        查询和增删都有, 需要元素自动排序的场景树的遍历:补充: 
代码中树节点的实现// 树的节点 
class Entry<T> { 
        T data;           // 存储的数据 
        Entry left;       // 左子节点的地址值 
        Entry right;      // 右子节点的地址值 
        Entry parent;     // 父节点的地址值 
} 
 List集合 
 List介绍和常用方法知识点: 
List集合体系有什么特点 
List接口中特有的按照索引操作的方法有哪些 
总结: 
List集合体系的特点:  
        1. 元素存取有序 (存入和取出元素的顺序一致) 321->321  排序: 从小到大 
        2. 元素可以重复  1 1 1 1 
        3. 有索引 
List子体系中的实现类都具有上述特点java.util.List接口: 
        // 常用特有成员方法 (都是按照索引来操作的)    
        void add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上 
        E get(int index): 返回集合中指定位置的元素 
        E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素 
        E set(int index, E element): 用指定元素替换集合中指定位置的元素, 返回值的更新前的元素 
补充: ArrayList集合的特点知识点: 
ArrayList底层使用的是什么数据结构, 有什么特点 
ArrayList适用于什么场景 
总结: 
ArrayList底层的数据结构:  
        数组 
         
ArrayList的特点: 
        查询快 
        增删慢 
        线程不安全, 效率高 
         
ArrayList适用场景: 
        存储的数据"查询多, 增删少"的场景. 如用一个ArrayList存储中国城市名称 
补充: LinkedList集合的特点和特有方法知识点: 
LinkedList底层使用的是什么数据结构, 有什么特点 
LinkedList适用于什么场景 
LinkedList有哪些特有方法 
总结: 
LinkedList底层的数据结构:  
        链表 
         
LinkedList的特点: 
        查询慢 
        增删快 
        线程不安全, 效率高 
         
LinkedList适用场景: 
        存储的数据"查询少, 增删多"的场景. 如用LinkedList实现栈或队列 
         
java.util.LinkedList<E>类: 链表结构, 查询慢, 增删快 
        // 特有成员方法(主要操作开头和末尾元素) 
        void addFirst(E e): 将指定元素插入此列表的开头 
        void addLast(E e): 将指定元素添加到此列表的结尾 
        E getFirst(): 返回此列表的第一个元素 
        E getLast(): 返回此列表的最后一个元素 
        E removeFirst(): 移除并返回此列表的第一个元素 
        E removeLast(): 移除并返回此列表的最后一个元素 
        E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 
        void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 
补充: 5分钟练习: 测试LinkedList特有方法 
需求: 
创建LinkedList集合, 添加元素1,2,3, 测试特有方法: 
        void addFirst(E e): 将指定元素插入此列表的开头 
        void addLast(E e): 将指定元素添加到此列表的结尾 
        E getFirst(): 返回此列表的第一个元素 
        E getLast(): 返回此列表的最后一个元素 
        E removeFirst(): 移除并返回此列表的第一个元素 
        E removeLast(): 移除并返回此列表的最后一个元素 
        E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 
        void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 
代码: 
public class Test { 
    public static void main(String[] args) { 
        // 创建LinkedList集合 
        LinkedList<Integer> linked = new LinkedList<>();        // 添加元素1,2,3 
        //void addFirst(E e): 将指定元素插入此列表的开头 
        linked.addFirst(1); 
        linked.addFirst(2); 
        linked.addFirst(3); 
        System.out.println(linked);  // 都是添加到头部, 所以是 3 2 1        // void addLast(E e): 将指定元素添加到此列表的结尾 
        linked.addLast(7); 
        linked.addLast(8); 
        linked.addLast(9); 
        System.out.println(linked);  // 都是添加到末尾, 所以是 3 2 1 7 8 9        // E getFirst(): 返回此列表的第一个元素 
        System.out.println(linked.getFirst());  // 3        // E getLast(): 返回此列表的最后一个元素 
        System.out.println(linked.getLast());  // 9        // E removeFirst(): 移除并返回此列表的第一个元素 
        Integer i1 = linked.removeFirst(); 
        System.out.println("删除开头:" + i1);  // 3        // E removeLast(): 移除并返回此列表的最后一个元素 
        Integer i2 = linked.removeLast(); 
        System.out.println("删除末尾:" + i2);  // 9        // E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 
        Integer pop = linked.pop(); 
        System.out.println("pop()取出的是:" + pop);  // 2        // void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 
        linked.push(666); 
        System.out.println(linked);  // [666, 1, 7, 8] 
    } 
} 
 Vector集合知识点: 
Vector底层使用的是什么数据结构, 有什么特点 
总结: 
JDK 1.0 版本中只有一个 Vector集合 
JDK 1.2 开始增加了Collection集合体系Vector底层的数据结构:  
        数组 
         
Vector的特点: 
        查询慢 
        增删快 
        (同步)线程安全, 效率低 
         
Vector目前几乎没人使用 
补充: Set集合体系 
 HashSet集合知识点: 
Set集合体系有什么特点 
HashSet有什么特点, 底层采用什么数据结构 
HashSet中的 boolean add(E e) 方法有什么特殊之处 
总结: 
Set集合体系特点: 
        1. 元素不可重复 
        2. 没有索引 
         
HashSet特点: 
        1. 元素不可重复 
        2. 没有索引 
        3. 元素存取无序 (存入和取出顺序有可能不一致) 
        4. 底层采用 哈希表 结构. (查询快) 
                哈希表 = 数组 + 链表或红黑树java.util.HashSet类: 
        // 常用方法 
        boolean add(E e): 添加元素, 根据元素的 hashCode() 和 equals() 方法判断是否重复. 重复则不添加并返回false, 不重复则添加并返回true 
补充: 5分钟练习: 使用HashSet添加元素 
需求: 
创建HashSet对象, 存储 5,5,4,4,3,3,2,2,1,1, 使用增强for遍历HashSet集合打印元素, 查看是否和存入顺序一致, 是否有重复元素 
代码:  
public class Test { 
    public static void main(String[] args) { 
        // 创建HashSet对象 
        HashSet<Integer> hashSet = new HashSet<>();        // 添加元素 
        hashSet.add(5); 
        hashSet.add(5); 
        hashSet.add(4); 
        hashSet.add(4); 
        hashSet.add(3); 
        hashSet.add(3); 
        hashSet.add(2); 
        hashSet.add(2); 
        hashSet.add(1); 
        hashSet.add(1);        // 使用增强for遍历HashSet集合打印元素 
        for (Integer i : hashSet) { 
            System.out.println(i); 
        }        /* 
            1 
            2 
            3 
            4 
            5 
         */ 
    } 
} 
 HashSet原理: 哈希值知识点: 
什么是哈希值, 哈希值有什么作用 
Object类中的 int hashCode() 方法有什么作用 
总结: 
哈希值: 
        一个十进制数值, 一般是通过将该对象的内部地址转换成一个整数来实现的public native int hashCode(); 
        可以调用系统本地代码(C/C++)计算出一个对象地址的哈希值 
         
hashCode()方法的作用 
        方法内部的算法用于将对象计算为一个哈希值, 便于根据哈希值比较对象是否"相等" 
        哈希值主要是为了提高对象存储在 哈希表 中的效率 
         
注意: 
        1. 如果我们不满意Object中的哈希值计算方法, 可以重写hashCode()方法.  
       但在Java代码中不能直接重写带有 native 的方法, 重写时应该将 native 去掉 
                        @Override 
                        public int hashCode() {} 
        2. hashCode() 方法有可能将"不同的对象"计算出"相同的哈希值", 这称为"哈希冲突", 在出现冲突后, 一般再通过 equals() 方法来继续判断对象是否"相等" 
         
        "重地"  "通话" 
补充: HashSet原理: 哈希表结构知识点: 
JDK 8以前, 哈希表是什么结构 
JDK 8及之后, 哈希表是什么结构 
总结: 
哈希表: 
        JDK 8以前   : 哈希表 = 数组 + 链表 
        JDK 8及之后 : 哈希表 = 数组 + 链表或红黑树 
        数组中存储的每个元素, 是哈希值相同的一组节点的链表或红黑树.bmp)补充: HashSet原理: 存储元素不重复的原理知识点: 
HashSet集合是如何保证添加元素时不能重复的 
总结: 
HashSet集合保证添加元素不重复的原理: 
        调用 add(E e) 添加元素时, 先调用 hashCode() 获取哈希值, 和当前HashSet集合中的元素比较 
                如果哈希值不同, 则认为元素不重复, 添加, 并返回true 
                如果哈希值相同, 则可能是哈希冲突, 所以继续调用元素的 equals() 方法和所有哈希值相同的元素比较 
                        如果 equals() 比较所有元素都没有相同的, 则认为元素不重复, 添加, 并返回true 
                        如果 equals() 比较出有相同的元素, 则认为元素重复, 不添加, 并返回false补充: HashSet存储自定义元素的去重知识点: 
我们自定义的JavaBean对象存入HashSet时, 想"根据属性值保证不重复", 应该怎么做 
总结: 
自定义JavaBean对象实现在HashSet中去重: 
        JavaBean默认继承Object类中的 hashCode() 和 equals() 方法, 都是根据对象地址值判断是否重复的 
        要根据属性值判断是否重复, 应该在JavaBean类中重写 hashCode() 和 equals() 方法, 使其按照属性值比较 
补充: 5分钟练习: 自定义Person类存入HashSet实现去重 
需求: 
定义Person类: 
        私有成员变量: 姓名String name, 年龄int age 
        生成无参/有参构造, set/get方法, toString()方法 
        生成 hashCode() 和 equals() 方法 
定义测试类 
        创建3个Person对象, 其中2个对象的姓名和年龄均相同, 另外1个对象姓名或年龄不同 
        创建HashSet集合, 存入3个Person对象, 打印HashSet集合, 查看是否去重 
代码: 
public class Person {    private String name; 
    private int age;    public Person() { 
    }    public Person(String name, int age) { 
        this.name = name; 
        this.age = age; 
    }    public String getName() { 
        return name; 
    }    public void setName(String name) { 
        this.name = name; 
    }    public int getAge() { 
        return age; 
    }    public void setAge(int age) { 
        this.age = age; 
    }    @Override 
    public String toString() { 
        return "Person{" + 
                "name='" + name + '\'' + 
                ", age=" + age + 
                '}'; 
    }    // 若要实现去重, 要生成: Alt + Insert 选择 equals() and hashCode()    @Override 
    public boolean equals(Object o) { 
        if (this == o) return true; 
        if (o == null || getClass() != o.getClass()) return false; 
        Person person = (Person) o; 
        return age == person.age && 
                Objects.equals(name, person.name); 
    }    @Override 
    public int hashCode() { 
        return Objects.hash(name, age); 
    } 
}public class Test { 
    public static void main(String[] args) { 
        // 创建3个Person对象 
        Person p1 = new Person("张三", 13); 
        Person p2 = new Person("张三", 13); 
        Person p3 = new Person("李四", 13);        // 创建HashSet集合 
        HashSet<Person> set = new HashSet<>();        set.add(p1); 
        set.add(p2); 
        set.add(p3);        // 打印 
        System.out.println(set); 
        // [Person{name='张三', age=13}, Person{name='李四', age=13}] 
    } 
} 
 LinkedHashSet集合知识点: 
LinkedHashSet有什么特点 
LinkedHashSet底层是什么数据结构 
总结: 
LinkedHashSet特点: 
        1. 元素存取有序 (存入和取出顺序一致) 
        2. 元素不可重复 
        3. 没有索引 
         
LinkedHashSet底层数据结构: 
        哈希表 + 链表   (也就是: 数组 + 链表或红黑树 + 链表) 
        其中, 哈希表用于存储数据, 额外的链表用于记录元素添加时的先后顺序, 以便在获取元素时保持顺序一致 
补充: 
总结: 什么时候用List, 什么时候用Set? 
        要存储的元素可以重复的, 用List集合: 
                增删少, 用ArrayList 
                增删多, 用LinkedList 
        要存储的数据要求不重复, 或者相对一个集合去重, 用Set集合: 
                不要求存取顺序一致, 用HashSet 
                要求存取顺序一致, 用LinkedHashSet 
 5分钟练习: 使用LinkedHashSet存储元素 
需求: 
创建LinkedHashSet对象, 存储 5,5,4,4,3,3,2,2,1,1, 使用增强for遍历LinkedHashSet集合打印元素, 查看是否和存入顺序一致 
代码: 
public class Test { 
    public static void main(String[] args) { 
        // 创建LinkedHashSet对象 
        LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();        // 添加元素 
        linkedHashSet.add(5); 
        linkedHashSet.add(5); 
        linkedHashSet.add(4); 
        linkedHashSet.add(4); 
        linkedHashSet.add(3); 
        linkedHashSet.add(3); 
        linkedHashSet.add(2); 
        linkedHashSet.add(2); 
        linkedHashSet.add(1); 
        linkedHashSet.add(1);        // 遍历 
        for (Integer i : linkedHashSet) { 
            System.out.println(i); 
        } 
        // 去重了, 并同时保证了存取顺序一致 
        /* 
            5 
            4 
            3 
            2 
            1 
         */ 
    } 
} 
 可变参数知识点: 
什么是可变参数 
可变参数用在哪里, 格式是什么 
可变参数的本质是什么 
可变参数可以传递的参数个数有什么要求 
可变参数的定义位置有什么要求 
总结: 
可变参数: 
        JDK 5 出现. 指同一个类型的参数, "个数可变" 
        可变参数的本质就是一个"数组" 
         
        格式: 用在方法的参数中 
            修饰符 返回值类型 方法名(int... 变量名) { 
                    // 可以直接将 变量名 当作 数组名 使用 
            } 
            方法名();注意事项: 
        1. 可变参数可以传递的参数个数, 可以是 0个, 1个, 多个 
        2. 一个方法的参数列表中, 只能有一个可变参数 
        3. 如果方法的参数有多个, 可变参数必须写在参数列表的最后 
补充: Collections集合工具类 
 Collections集合工具类: addAll(), shuffle()知识点: 
Collections集合工具类的常用方法有哪些 
总结: 
java.util.Collections类: 操作集合的工具类 
        // 静态方法 
        static <T> boolean addAll(Collection<? super T> c, T... elements):往集合中添加一些元素 
        static void shuffle(List<?> list): 打乱集合顺序 
        static <T> void sort(List<T> list): 将集合中元素按照默认规则排序 
        static <T> void sort(List<T> list,Comparator<? super T> c):将集合中元素按照指定规则排序 
补充: 5分钟练习: 测试addAll()和shuffle()方法 
需求: 
创建ArrayList集合, 使用 Collections.addAll() 方法, 向集合中添加1,2,3,4,5 
然后调用shuffle()方法打乱该集合的顺序, 打印集合查看效果 
代码: 
public class Test { 
    public static void main(String[] args) { 
        // 创建集合 
        ArrayList<Integer> list = new ArrayList<>();        // 添加多个元素 
        Collections.addAll(list, 1, 2, 3, 4, 5);        // 打乱 
        Collections.shuffle(list);        // 打印 
        System.out.println(list); 
    } 
} Collections集合工具类: sort(List<T> list)知识点: 
void sort(List<T> list) 方法按照什么规则将元素排序 
是不是所有类型的元素都能排序 
该方法有什么使用前提 
自定义JavaBean对象要想排序, 需要怎么做 
总结: 
sort(List<T> list): 默认按照"升序"将元素排序 
        数字, 字母, 都可以按照升序排序 
         
自定义JavaBean对象默认不能排序, 因为不知道如何比较哪个对象大, 哪个对象小 
自定义JavaBean对象要想排序, 需要实现 Comparable<E> 接口, 重写 int compareTo(E e) 方法 
        规则: 
                this-参数: 升序(从小到大) 
                参数-this: 降序(从大到小) 
补充: 5分钟练习: 实现Person排序 
需求: 
定义Person类, 实现Comparable接口, 泛型为Person: 
        私有成员变量: 姓名String name, 年龄int age 
        生成无参/有参构造, set/get方法, toString() 
        重写int compareTo(E e)方法 
                方法内部根据Person对象的年龄计算大小 
定义测试类 
        创建3个Person对象, 分别为: 
                李四, 14 
                张三, 13 
                王五, 15 
        创建ArrayList集合, 存储3个Person对象 
        调用 Collections.sort() 方法, 对集合排序, 然后使用增强for遍历输出结果, 查看是否排序 
代码: 
public class Person implements Comparable<Person>{  // 注意写上泛型    @Override 
    public int compareTo(Person o) { 
        return this.getAge() - o.getAge();  // 按照年龄升序排序 
    }    private String name; 
    private int age;    public Person() { 
    }    public Person(String name, int age) { 
        this.name = name; 
        this.age = age; 
    }    public String getName() { 
        return name; 
    }    public void setName(String name) { 
        this.name = name; 
    }    public int getAge() { 
        return age; 
    }    public void setAge(int age) { 
        this.age = age; 
    }    @Override 
    public String toString() { 
        return "Person{" + 
                "name='" + name + '\'' + 
                ", age=" + age + 
                '}'; 
    } 
}public class Test { 
    public static void main(String[] args) { 
        // 创建3个Person对象 
        Person p1 = new Person("李四", 14); 
        Person p2 = new Person("张三", 13); 
        Person p3 = new Person("王五", 15);        // 创建集合 
        ArrayList<Person> list = new ArrayList<>(); 
        list.add(p1); 
        list.add(p2); 
        list.add(p3); 
        System.out.println("排序前:" + list);        // 排序 
        Collections.sort(list); 
        System.out.println("排序后:" + list); 
        /* 
排序前:[Person{name='李四', age=14}, Person{name='张三', age=13}, Person{name='王五', age=15}] 
排序后:[Person{name='张三', age=13}, Person{name='李四', age=14}, Person{name='王五', age=15}] 
         */ 
    } 
} 
 Collections集合工具类: sort(List<T> list,Comparator<? super T> )知识点: 
void sort(List<T> list,Comparator<? super T> c) 方法的第二个参数是什么, 如何使用 
Comparable接口和Comparator接口有什么区别 
自定义JavaBean对象要想利用该方法排序, 需要怎么做 
总结: 
Comparable接口和Comparator接口区别 
        Comparable: 让JavaBean自身具有可比较性 (自己和其他人比) 
        Comparator: 定义一个比较器类, 用比较器对象比 (让第三个人来帮两个人比较)Comparator使用方式: 
        1. 定义类实现Comparator<E>接口, 重写 int compare(E o1, E o2) 方法, 泛型为比较元素的类型 
                规则: 
            o1-o2: 升序(从小到大) 
            o2-o1: 降序(从大到小) 
        2. 在Collections.sort(List<T> list,Comparator<? super T> c)方法中传入自定义比较器对象 
补充: 5分钟练习: 使用Comparator对Person集合排序 
需求: 
定义Person类: 
        私有成员变量: 姓名String name, 年龄int age 
        生成无参/有参构造, set/get方法, toString() 
定义测试类 
        创建3个Person对象, 分别为: 
                李四, 14 
                张三, 13 
                王五, 15 
        创建ArrayList集合, 存储3个Person对象 
        调用Collections.sort(List<T> list,Comparator<? super T> c)方法, 对集合排序, 比较器使用匿名内部类对象方式, 按照Person对象的年龄排序 
        然后使用增强for遍历输出结果, 查看是否排序 
代码: 
public class Person {    private String name; 
    private int age;    public Person() { 
    }    public Person(String name, int age) { 
        this.name = name; 
        this.age = age; 
    }    public String getName() { 
        return name; 
    }    public void setName(String name) { 
        this.name = name; 
    }    public int getAge() { 
        return age; 
    }    public void setAge(int age) { 
        this.age = age; 
    }    @Override 
    public String toString() { 
        return "Person{" + 
                "name='" + name + '\'' + 
                ", age=" + age + 
                '}'; 
    } 
}public class Test { 
    public static void main(String[] args) { 
        // 创建Person对象 
        Person p1 = new Person("李四", 14); 
        Person p2 = new Person("张三", 13); 
        Person p3 = new Person("王五", 15);        // 创建ArrayList 
        ArrayList<Person> list = new ArrayList<>();        list.add(p1); 
        list.add(p2); 
        list.add(p3); 
        System.out.println("排序前:" + list);        // 排序 
        Collections.sort(list, new Comparator<Person>() { 
            @Override 
            public int compare(Person o1, Person o2) { 
                return o1.getAge() - o2.getAge(); // 按照年龄升序 
            } 
        });        System.out.println("排序后:" + list); 
    } 
} 
 今日API 
java.util.List<E>接口: 
        // 常用特有成员方法 (都是按照索引来操作的) 
        public void add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上 
        public E get(int index): 返回集合中指定位置的元素 
        public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素 
        public E set(int index, E element): 用指定元素替换集合中指定位置的元素, 返回值的更新前的元素java.util.LinkedList<E>类: 链表结构, 查询慢, 增删快 
        // 特有成员方法(主要操作开头和末尾元素) 
        void addFirst(E e): 将指定元素插入此列表的开头 
        void addLast(E e): 将指定元素添加到此列表的结尾 
        E getFirst(): 返回此列表的第一个元素 
        E getLast(): 返回此列表的最后一个元素 
        E removeFirst(): 移除并返回此列表的第一个元素 
        E removeLast(): 移除并返回此列表的最后一个元素 
        E pop(): (其实就是removeFirst())从此列表所表示的堆栈处弹出一个元素 栈stack 
        void push(E e): (其实就是addFirst())将元素推入此列表所表示的堆栈 
         
java.util.Set<E>接口: 
        // 成员方法 
        boolean add(E e): 添加元素. 元素不重复则添加成功, 返回true; 否则返回false 
         
java.util.Collections类: 操作集合的工具类 
        // 静态方法 
        static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素 
        static void shuffle(List<?> list) :打乱集合顺序 
        static <T> void sort(List<T> list) :将集合中元素按照默认规则排序 
        static <T> void sort(List<T> list,Comparator<? super T> c):将集合中元素按照指定规则排序 
**单列集合体系:** 
Collection接口: 单列集合的根接口, 规定了公共的功能 
        | 
        |_ List接口: 元素存取有序, 可重复, 有索引 
        |        |_ Vector类: 底层数组, 有索引, 内存空间连续分配, 查询快, 增删慢, 线程安全, 效率低 
        |        |_ ArrayList类: 底层数组, 有索引, 内存空间连续分配, 查询快, 增删慢, 线程不安全, 效率高 
        |        |_ LinkedList类: 底层链表, 查询慢, 增删快 
        |        |_ 遍历 
        |                - toArray(): 可以 
        |                - 普通for: 可以 
        |                - 增强for: 可以 
        |                - 迭代器: 可以 
        | 
        |_ Set接口: 元素不可重复, 无索引 
                |_ HashSet类: 底层哈希表, 元素无序, 元素不可重复(用hashCode()和equals()方法来判断) 
                |        |_ LinkedHashSet类: 哈希表+链表, 同时具有HashSet的元素不重复, 链表存取有序的特点 
                | 
                |_ TreeSet类: 底层红黑树结构(存入元素时就会按照元素自然顺序排序). 
                |         
                |_ 遍历 
                        - toArray(): 可以 
                        - 普通for: 不可以, 没有索引, 不能用! 
                        - 增强for: 可以 
                        - 迭代器: 可以 
 今日目标 能够说出List集合特点 
        1. 元素存取有序 
        2. 可以存储重复元素 
        3. 有索引 
 能够说出常见的数据结构 
        栈 
        队列 
        数组 
        链表 
        红黑树 
        哈希表 
 能够说出数组结构特点 
        查询快, 增删慢 
 能够说出栈结构特点 
        先进后出 
        出口和入口在同一侧 
 能够说出队列结构特点 
        先进先出 
        出口和入口在两侧 
 能够说出单向链表结构特点 
        由节点组成 
        遍历: 从开头一直到末尾查询慢, 增删快 
 能够说出Set集合的特点 
        1. 元素不能重复 
        2. 没有索引 
 能够说出哈希表的特点 
        哈希表 = 数组 + 链表/红黑树去重: 
        add() 先使用hashCode()方法计算哈希值, 判断哈希值是否有重复 
                如果没有重复的, 说明没有重复, 直接添加 
                如果有重复的哈希值, 是哈希冲突, 继续使用元素的equals()方法来判断是否重复 
                        如果 equals()判断全都不一样, 说明不重复, 可以添加 
                        如果 equals()判断有重复的, 说明重复, 不能添加 
 使用HashSet集合存储自定义元素 
        HashSet: 去重自定义元素要重写 hashCode() equals()方法 
 能够说出可变参数的格式 
        方法名(数据类型... 变量名) { 
                        // 当作数组来使用 
        }注意事项: 
                参数列表中只能有1个可变参数 
                放在列表的最后 
                传递参数的个数0~n个 
 能够使用集合工具类 
        Collections类 
                static boolean addAll(Collection c, T... t) 
                static void shuffle(List list) 
                static void sort(List list): 元素实现Comparable接口 
                static void sort(List list, Comparator c) 
 能够使用Comparator比较器进行排序 
        1. 定义实现类实现Comparator接口, 重写 int compare(E o1, E o2) 
                规则: 
                        o1-o2 升序 
                        o2-o1 降序 
2. 创建实现类对象, 传递到 static void sort(List list, Comparator c) 方法中 |   
        
 
    
    
    
     
 
 |