1、集合概述
    1.1、什么是集合?有什么用?
    数组其实就是一个集合。集合实际上就是一个容器。可以来容纳其它类型的数据。
    集合为什么说在开发中使用较多?
    集合是一个容器,是一个载体,可以一次容纳多个对象。
    在实际开发中,假设连接数据库,数据库当中有10条记录,
    那么假设把这10条记录查询出来,在java程序中会将10条
    数据封装成10个java对象,然后将10个java对象放到某一个
    集合当中,将集合传到前端,然后遍历集合,将一个数据一个
    数据展现出来。
    1.2、集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,
    集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用。)
    list.add(100); //自动装箱Integer
    注意:
    集合在java中本身是一个容器,是一个对象。
    集合中任何时候存储的都是“引用”。
    1.3、在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中
    存储元素,等于将数据放到了不同的数据结构当中。什么是数据结构?数据存储的
    结构就是数据结构。不同的数据结构,数据存储方式不同。例如:
    数组、二叉树、链表、哈希表…
    以上这些都是常见的数据结构。
    你往集合c1中放数据,可能是放到数组上了。
    你往集合c2中放数据,可能是放到二叉树上了。
    …..
    你使用不同的集合等同于使用了不同的数据结构。
    你在java集合这一章节,你需要掌握的不是精通数据结构。java中已经将数据结构
    实现了,已经写好了这些常用的集合类,你只需要掌握怎么用?在什么情况下选择
    哪一种合适的集合去使用即可。
    new ArrayList(); 创建一个集合,底层是数组。
    new LinkedList(); 创建一个集合对象,底层是链表。
    new TreeSet(); 创建一个集合对象,底层是二叉树。
    …..
    1.4、集合在java JDK中哪个包下?
    java.util.*;
    所有的集合类和集合接口都在java.util包下。

    1.5、为了让大家掌握集合这块的内容,最好能将集合的继承结构图背会!!!
    集合整个这个体系是怎样的一个结构,你需要有印象。
    1.6、在java中集合分为两大类:
    一类是单个方式存储元素:
    单个方式存储元素,这一类集合中超级父接口:java.util.Collection;
    一类是以键值对儿的方式存储元素
    以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;
    2、总结重点:
    第一个重点:把集合继承结构图背会。
    第二个重点:把Collection接口中常用方法测试几遍。
    第三个重点:把迭代器弄明白。
    第四个重点:Collection接口中的remove方法和contains方法底层都会调用equals,
    这个弄明白。

    image.png

    image.png

    总结(所有的实现类):
    n ArrayList:底层是数组。
    n LinkedList:底层是双向链表。
    n Vector:底层是数组,线程安全的,效率较低,使用较少。
    n HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了。
    n TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了。
    n HashMap:底层是哈希表。
    n Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。
    n Properties:是线程安全的,并且key和value只能存储字符串String。
    n TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。

    List集合存储元素的特点:
    有序可重复
    有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。
    可重复:存进去1,可以再存储一个1.

    Set(Map)集合存储元素的特点:
    无序不可重复
    无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
    不可重复:存进去1,不能再存储1了。

    SortedSet(SortedMap)集合存储元素特点:
    首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
    无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
    不可重复:存进去1,不能再存储1了。
    可排序:可以按照大小顺序排列。

    Map集合的key,就是一个Set集合。
    往Set集合中放数据,实际上放到了Map集合的key部分。

    3.自定义泛型

    1. package com.bjpowernode.javase.pratice;
    2. //定义泛型 一般采用 T 和E t代表type e代表element
    3. public class Fine<E> {
    4. //规定方法参数类型
    5. public void run(E a){
    6. System.out.println("run");
    7. }
    8. //规定方法返回值类型
    9. public E eat(){
    10. return null;
    11. }
    12. public static void main(String[] args) {
    13. Fine<String> fine =new Fine<>();
    14. fine.run("11");
    15. Fine<Integer> aa=new Fine<>();
    16. aa.run(11);
    17. aa.eat();
    18. }
    19. }

    4.增强for循环

    1. package com.bjpowernode.javase.collection;
    2. import java.util.ArrayList;
    3. import java.util.Iterator;
    4. import java.util.List;
    5. /*
    6. 集合使用foreach
    7. */
    8. public class ForEachTest02 {
    9. public static void main(String[] args) {
    10. // 创建List集合
    11. List<String> strList = new ArrayList<>();
    12. // 添加元素
    13. strList.add("hello");
    14. strList.add("world!");
    15. strList.add("kitty!");
    16. // 遍历,使用迭代器方式
    17. Iterator<String> it = strList.iterator();
    18. while(it.hasNext()){
    19. String s = it.next();
    20. System.out.println(s);
    21. }
    22. // 使用下标方式(只针对于有下标的集合)
    23. for(int i = 0; i < strList.size(); i++){
    24. System.out.println(strList.get(i));
    25. }
    26. // 使用foreach
    27. for(String s : strList){ // 因为泛型使用的是String类型,所以是:String s
    28. System.out.println(s);
    29. }
    30. List<Integer> list = new ArrayList<>();
    31. list.add(100);
    32. list.add(200);
    33. list.add(300);
    34. for(Integer i : list){ // i代表集合中的元素
    35. System.out.println(i);
    36. }
    37. }
    38. }

    5.map集合的遍历

    1. package com.bjpowernode.javase.pratice;
    2. import java.util.HashMap;
    3. import java.util.Iterator;
    4. import java.util.Map;
    5. import java.util.Set;
    6. public class MapTest {
    7. public static void main(String[] args) {
    8. //1.创建一个map集合
    9. Map<Integer,String> map=new HashMap<>();
    10. //2.往集合中添加元素
    11. map.put(1,"张三");
    12. map.put(2,"李四");
    13. //获取元素的key
    14. Set<Integer> keys = map.keySet();
    15. //通过构造器遍历集合
    16. Iterator<Integer> iterator = keys.iterator();
    17. while (iterator.hasNext()){
    18. int key=iterator.next();
    19. String value=map.get(key);
    20. System.out.println(key+":"+value);
    21. }
    22. //增强for循环遍历集合
    23. for (Integer key:keys
    24. ) {
    25. System.out.println(key+":"+map.get(key));
    26. }
    27. //特有的方法遍历集合
    28. Set<Map.Entry<Integer, String>> entries = map.entrySet();
    29. for (Map.Entry<Integer,String> entry:entries){
    30. System.out.println(entry.getKey()+entry.getValue());
    31. }
    32. }
    33. }

    6.hash表或散列表的数据结构
    day30-哈希表或者散列表数据结构.png
    7.map接口的常用方法

    1. package com.bjpowernode.javase.collection;
    2. import java.util.Collection;
    3. import java.util.HashMap;
    4. import java.util.Map;
    5. /*
    6. java.util.Map接口中常用的方法:
    7. 1、Map和Collection没有继承关系。
    8. 2、Map集合以key和value的方式存储数据:键值对
    9. key和value都是引用数据类型。
    10. key和value都是存储对象的内存地址。
    11. key起到主导的地位,value是key的一个附属品。
    12. 3、Map接口中常用方法:
    13. V put(K key, V value) 向Map集合中添加键值对
    14. V get(Object key) 通过key获取value
    15. void clear() 清空Map集合
    16. boolean containsKey(Object key) 判断Map中是否包含某个key
    17. boolean containsValue(Object value) 判断Map中是否包含某个value
    18. boolean isEmpty() 判断Map集合中元素个数是否为0
    19. V remove(Object key) 通过key删除键值对
    20. int size() 获取Map集合中键值对的个数。
    21. Collection<V> values() 获取Map集合中所有的value,返回一个Collection
    22. Set<K> keySet() 获取Map集合所有的key(所有的键是一个set集合)
    23. Set<Map.Entry<K,V>> entrySet()
    24. 将Map集合转换成Set集合
    25. 假设现在有一个Map集合,如下所示:
    26. map1集合对象
    27. key value
    28. ----------------------------
    29. 1 zhangsan
    30. 2 lisi
    31. 3 wangwu
    32. 4 zhaoliu
    33. Set set = map1.entrySet();
    34. set集合对象
    35. 1=zhangsan 【注意:Map集合通过entrySet()方法转换成的这个Set集合,Set集合中元素的类型是 Map.Entry<K,V>】
    36. 2=lisi 【Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态内部类】
    37. 3=wangwu
    38. 4=zhaoliu ---> 这个东西是个什么?Map.Entry
    39. */
    40. public class MapTest01 {
    41. public static void main(String[] args) {
    42. // 创建Map集合对象
    43. Map<Integer, String> map = new HashMap<>();
    44. // 向Map集合中添加键值对
    45. map.put(1, "zhangsan"); // 1在这里进行了自动装箱。
    46. map.put(2, "lisi");
    47. map.put(3, "wangwu");
    48. map.put(4, "zhaoliu");
    49. // 通过key获取value
    50. String value = map.get(2);
    51. System.out.println(value);
    52. // 获取键值对的数量
    53. System.out.println("键值对的数量:" + map.size());
    54. // 通过key删除key-value
    55. map.remove(2);
    56. System.out.println("键值对的数量:" + map.size());
    57. // 判断是否包含某个key
    58. // contains方法底层调用的都是equals进行比对的,所以自定义的类型需要重写equals方法。
    59. System.out.println(map.containsKey(new Integer(4))); // true
    60. // 判断是否包含某个value
    61. System.out.println(map.containsValue(new String("wangwu"))); // true
    62. // 获取所有的value
    63. Collection<String> values = map.values();
    64. // foreach
    65. for(String s : values){
    66. System.out.println(s);
    67. }
    68. // 清空map集合
    69. map.clear();
    70. System.out.println("键值对的数量:" + map.size());
    71. // 判断是否为空
    72. System.out.println(map.isEmpty()); // true
    73. }
    74. }

    8.map的结论

    1. package com.bjpowernode.javase.bean;
    2. import java.util.HashSet;
    3. import java.util.Set;
    4. /*
    5. 1、向Map集合中存,以及从Map集合中取,都是先调用key的hashCode方法,然后再调用equals方法!
    6. equals方法有可能调用,也有可能不调用。
    7. 拿put(k,v)举例,什么时候equals不会调用?
    8. k.hashCode()方法返回哈希值,
    9. 哈希值经过哈希算法转换成数组下标。
    10. 数组下标位置上如果是null,equals不需要执行。
    11. 拿get(k)举例,什么时候equals不会调用?
    12. k.hashCode()方法返回哈希值,
    13. 哈希值经过哈希算法转换成数组下标。
    14. 数组下标位置上如果是null,equals不需要执行。
    15. 2、注意:如果一个类的equals方法重写了,那么hashCode()方法必须重写。
    16. 并且equals方法返回如果是true,hashCode()方法返回的值必须一样。
    17. equals方法返回true表示两个对象相同,在同一个单向链表上比较。
    18. 那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的。
    19. 所以hashCode()方法的返回值也应该相同。
    20. 3、hashCode()方法和equals()方法不用研究了,直接使用IDEA工具生成,但是这两个方法需要同时生成。
    21. 4、终极结论:
    22. 放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
    23. 5、对于哈希表数据结构来说:
    24. 如果o1和o2的hash值相同,一定是放到同一个单向链表上。
    25. 当然如果o1和o2的hash值不同,但由于哈希算法执行结束之后转换的数组下标可能相同,此时会发生“哈希碰撞”。
    26. */
    27. public class HashMapTest02 {
    28. public static void main(String[] args) {
    29. Student s1 = new Student("zhangsan");
    30. Student s2 = new Student("zhangsan");
    31. // 重写equals方法之前是false
    32. //System.out.println(s1.equals(s2)); // false
    33. // 重写equals方法之后是true
    34. System.out.println(s1.equals(s2)); //true (s1和s2表示相等)
    35. System.out.println("s1的hashCode=" + s1.hashCode()); //284720968 (重写hashCode之后-1432604525)
    36. System.out.println("s2的hashCode=" + s2.hashCode()); //122883338 (重写hashCode之后-1432604525)
    37. // s1.equals(s2)结果已经是true了,表示s1和s2是一样的,相同的,那么往HashSet集合中放的话,
    38. // 按说只能放进去1个。(HashSet集合特点:无序不可重复)
    39. Set<Student> students = new HashSet<>();
    40. students.add(s1);
    41. students.add(s2);
    42. System.out.println(students.size()); // 这个结果按说应该是1. 但是结果是2.显然不符合HashSet集合存储特点。怎么办?
    43. }
    44. }

    9.面试题
    hashmap集合的key允许为null,但只能有一个
    hashtable的key和value不能为null

    20.properties

    package com.bjpowernode.javase.collection;
    
    import java.util.Properties;
    
    /*
    目前只需要掌握Properties属性类对象的相关方法即可。
    Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型。
    Properties被称为属性类对象。
    Properties是线程安全的。
     */
    public class PropertiesTest01 {
        public static void main(String[] args) {
    
            // 创建一个Properties对象
            Properties pro = new Properties();
    
            // 需要掌握Properties的两个方法,一个存,一个取。
            pro.setProperty("url", "jdbc:mysql://localhost:3306/bjpowernode");
            pro.setProperty("driver","com.mysql.jdbc.Driver");
            pro.setProperty("username", "root");
            pro.setProperty("password", "123");
    
            // 通过key获取value
            String url = pro.getProperty("url");
            String driver = pro.getProperty("driver");
            String username = pro.getProperty("username");
            String password = pro.getProperty("password");
    
            System.out.println(url);
            System.out.println(driver);
            System.out.println(username);
            System.out.println(password);
    
        }
    }
    

    21.treeset

    package com.bjpowernode.javase.collection;
    
    import java.util.TreeSet;
    
    /*
    1、TreeSet集合底层实际上是一个TreeMap
    2、TreeMap集合底层是一个二叉树。
    3、放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
    4、TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。
    称为:可排序集合。
     */
    public class TreeSetTest02 {
        public static void main(String[] args) {
            // 创建一个TreeSet集合
            TreeSet<String> ts = new TreeSet<>();
            // 添加String
            ts.add("zhangsan");
            ts.add("lisi");
            ts.add("wangwu");
            ts.add("zhangsi");
            ts.add("wangliu");
            // 遍历
            for(String s : ts){
                // 按照字典顺序,升序!
                System.out.println(s);
            }
    
            TreeSet<Integer> ts2 = new TreeSet<>();
            ts2.add(100);
            ts2.add(200);
            ts2.add(900);
            ts2.add(800);
            ts2.add(600);
            ts2.add(10);
            for(Integer elt : ts2){
                // 升序!
                System.out.println(elt);
            }
        }
    }
    
    /*
    数据库中有很多数据:
        userid  name     birth
        -------------------------------------
        1       zs          1980-11-11
        2       ls          1980-10-11
        3       ww          1981-11-11
        4       zl          1979-11-11
    
        编写程序从数据库当中取出数据,在页面展示用户信息的时候按照生日升序或者降序。
        这个时候可以使用TreeSet集合,因为TreeSet集合放进去,拿出来就是有顺序的。
     */
    

    22.treeset中对象之间比较要实现comparable接口 不然会报出异常

    package com.bjpowernode.javase.collection;
    
    import java.util.TreeSet;
    
    /*
    对自定义的类型来说,TreeSet可以排序吗?
        以下程序中对于Person类型来说,无法排序。因为没有指定Person对象之间的比较规则。
        谁大谁小并没有说明啊。
    
        以下程序运行的时候出现了这个异常:
            java.lang.ClassCastException:
                class com.bjpowernode.javase.collection.Person
                cannot be cast to class java.lang.Comparable
        出现这个异常的原因是:
            Person类没有实现java.lang.Comparable接口。
     */
    public class TreeSetTest03 {
        public static void main(String[] args) {
            Person p1 = new Person(32);
            //System.out.println(p1);
            Person p2 = new Person(20);
            Person p3 = new Person(30);
            Person p4 = new Person(25);
    
            // 创建TreeSet集合
            TreeSet<Person> persons = new TreeSet<>();
            // 添加元素
            persons.add(p1);
            persons.add(p2);
            persons.add(p3);
            persons.add(p4);
    
            // 遍历
            for (Person p : persons){
                System.out.println(p);
            }
        }
    }
    
    class Person {
        int age;
        public Person(int age){
            this.age = age;
        }
    
        // 重写toString()方法
        public String toString(){
            return "Person[age="+age+"]";
        }
    }
    

    23.实现comparable接口并且重写compareto方法

    package com.bjpowernode.javase.collection;
    
    import java.util.TreeSet;
    
    public class TreeSetTest04 {
        public static void main(String[] args) {
            Customer c1 = new Customer(32);
            Customer c2 = new Customer(20);
            Customer c3 = new Customer(30);
            Customer c4 = new Customer(25);
    
            // 创建TreeSet集合
            TreeSet<Customer> customers = new TreeSet<>();
            // 添加元素
            customers.add(c1);
            customers.add(c2);
            customers.add(c3);
            customers.add(c4);
    
            // 遍历
            for (Customer c : customers){
                System.out.println(c);
            }
        }
    }
    
    // 放在TreeSet集合中的元素需要实现java.lang.Comparable接口。
    // 并且实现compareTo方法。equals可以不写。
    class Customer implements Comparable<Customer>{
    
        int age;
        public Customer(int age){
            this.age = age;
        }
    
        // 需要在这个方法中编写比较的逻辑,或者说比较的规则,按照什么进行比较!
        // k.compareTo(t.key)
        // 拿着参数k和集合中的每一个k进行比较,返回值可能是>0 <0 =0
        // 比较规则最终还是由程序员指定的:例如按照年龄升序。或者按照年龄降序。
        @Override
        public int compareTo(Customer c) { // c1.compareTo(c2);
            // this是c1
            // c是c2
            // c1和c2比较的时候,就是this和c比较。
            /*int age1 = this.age;
            int age2 = c.age;
            if(age1 == age2){
                return 0;
            } else if(age1 > age2) {
                return 1;
            } else {
                return -1;
            }*/
            //return this.age - c.age; // =0 >0 <0
            return c.age - this.age;
        }
    
        public String toString(){
            return "Customer[age="+age+"]";
        }
    }
    
    package com.bjpowernode.javase.collection;
    
    import java.util.TreeSet;
    
    /*
    先按照年龄升序,如果年龄一样的再按照姓名升序。
     */
    public class TreeSetTest05 {
        public static void main(String[] args) {
            TreeSet<Vip> vips = new TreeSet<>();
            vips.add(new Vip("zhangsi", 20));
            vips.add(new Vip("zhangsan", 20));
            vips.add(new Vip("king", 18));
            vips.add(new Vip("soft", 17));
            for(Vip vip : vips){
                System.out.println(vip);
            }
        }
    }
    
    class Vip implements Comparable<Vip>{
        String name;
        int age;
    
        public Vip(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Vip{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        /*
        compareTo方法的返回值很重要:
            返回0表示相同,value会覆盖。
            返回>0,会继续在右子树上找。【10 - 9 = 1 ,1 > 0的说明左边这个数字比较大。所以在右子树上找。】
            返回<0,会继续在左子树上找。
         */
        @Override
        public int compareTo(Vip v) {
            // 写排序规则,按照什么进行比较。
            if(this.age == v.age){
                // 年龄相同时按照名字排序。
                // 姓名是String类型,可以直接比。调用compareTo来完成比较。
                return this.name.compareTo(v.name);
            } else {
                // 年龄不一样
                return this.age - v.age;
            }
        }
    }
    

    24.比较器

    package com.bjpowernode.javase.collection;
    
    import java.util.Comparator;
    import java.util.TreeSet;
    
    /*
    TreeSet集合中元素可排序的第二种方式:使用比较器的方式。
    最终的结论:
        放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:
            第一种:放在集合中的元素实现java.lang.Comparable接口。
            第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
    Comparable和Comparator怎么选择呢?
        当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议实现Comparable接口。
        如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。
    
        Comparator接口的设计符合OCP原则。
     */
    public class TreeSetTest06 {
        public static void main(String[] args) {
            // 创建TreeSet集合的时候,需要使用这个比较器。
            // TreeSet<WuGui> wuGuis = new TreeSet<>();//这样不行,没有通过构造方法传递一个比较器进去。
    
            // 给构造方法传递一个比较器。
            //TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());
    
            // 大家可以使用匿名内部类的方式(这个类没有名字。直接new接口。)
            TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
                @Override
                public int compare(WuGui o1, WuGui o2) {
                    return o1.age - o2.age;
                }
            });
    
            wuGuis.add(new WuGui(1000));
            wuGuis.add(new WuGui(800));
            wuGuis.add(new WuGui(810));
    
            for(WuGui wuGui : wuGuis){
                System.out.println(wuGui);
            }
        }
    }
    
    // 乌龟
    class WuGui{
    
        int age;
    
        public WuGui(int age){
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "小乌龟[" +
                    "age=" + age +
                    ']';
        }
    }
    
    // 单独在这里编写一个比较器
    // 比较器实现java.util.Comparator接口。(Comparable是java.lang包下的。Comparator是java.util包下的。)
    /*
    class WuGuiComparator implements Comparator<WuGui> {
    
        @Override
        public int compare(WuGui o1, WuGui o2) {
            // 指定比较规则
            // 按照年龄排序
            return o1.age - o2.age;
        }
    }
     */
    

    25.二叉树的数据结构
    day30-自平衡二叉树.png
    26.集合工具类

    package com.bjpowernode.javase.collection;
    
    import java.util.*;
    
    /*
    java.util.Collection 集合接口
    java.util.Collections 集合工具类,方便集合的操作。
     */
    public class CollectionsTest {
        public static void main(String[] args) {
    
            // ArrayList集合不是线程安全的。
            List<String> list = new ArrayList<>();
    
            // 变成线程安全的
            Collections.synchronizedList(list);
    
            // 排序
            list.add("abf");
            list.add("abx");
            list.add("abc");
            list.add("abe");
    
            Collections.sort(list);
            for(String s : list){
                System.out.println(s);
            }
    
            List<WuGui2> wuGuis = new ArrayList<>();
            wuGuis.add(new WuGui2(1000));
            wuGuis.add(new WuGui2(8000));
            wuGuis.add(new WuGui2(500));
            // 注意:对List集合中元素排序,需要保证List集合中的元素实现了:Comparable接口。
            Collections.sort(wuGuis);
            for(WuGui2 wg : wuGuis){
                System.out.println(wg);
            }
    
            // 对Set集合怎么排序呢?
            Set<String> set = new HashSet<>();
            set.add("king");
            set.add("kingsoft");
            set.add("king2");
            set.add("king1");
            // 将Set集合转换成List集合
            List<String> myList = new ArrayList<>(set);
            Collections.sort(myList);
            for(String s : myList) {
                System.out.println(s);
            }
    
            // 这种方式也可以排序。
            //Collections.sort(list集合, 比较器对象);
        }
    }
    
    class WuGui2 implements Comparable<WuGui2>{
        int age;
        public WuGui2(int age){
            this.age = age;
        }
    
        @Override
        public int compareTo(WuGui2 o) {
            return this.age - o.age;
        }
    
        @Override
        public String toString() {
            return "WuGui2{" +
                    "age=" + age +
                    '}';
        }
    }