【Java学习笔记】

集合进阶

集合体系结构

Collection(单列集合,为接口)

  1. List(接口)
    • ArrayList(实现类)
    • LinkedList(实现类)
    • Vector(实现类)
  2. Set(接口)
    • HashSet(实现类):无序、不重复、无索引
      • LinkedHashSet(实现类):有序、不重复、无索引
    • TreeSet(实现类):可排序、不重复、无索引
  3. List系列集合:添加的元素是有序(存取)、有索引、可重复的。
  4. Set系列集合:添加的元素是无序(存取有可能不一样)、无索引、不可重复的,Set接口中的方法基本上与Collection的API一致。

Map(双列集合)

Collection集合

  1. Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。

    方法名称说明
    public boolean add(E e)把给定的对象添加到当前集合中
    public void clear()清空集合中所有的元素
    public boolean remove(E e)把给定的对象在当前集合中删除
    public boolean contains(Object obj)判断当前集合中是否包含给定的对象
    public boolean isEmpty()判断当前集合是否为空
    public int size()返回集合中元素的个数/集合的长度
    public class CollectionDemo01 {
        public static void main(String[] args) {
            /*
                public boolean add(E e)              把给定的对象添加到当前集合中
                public void clear()                  清空集合中所有的元素
                public boolean remove(E e)           把给定的对象在当前集合中删除
                public boolean contains(Object obj)  判断当前集合中是否包含给定的对象
                public boolean isEmpty()             判断当前集合是否为空
                public int size()                    返回集合中元素的个数/集合的长度
    
                注意点:
                    Collection是一个接口,我们不能直接创建它的对象
                    所以,现在我们学习它的方法时,只能创建它实现类的对象
                    实现类:ArrayList
             */
    
            //目的:为了学习Collection接口里的方法
            //自己在做一些练习的时候,还是按照之前的方法去创建对象
            Collection<String> coll = new ArrayList<>();
    
            //1.添加元素
            //细节1:如果我们要往List系列集合中添加数据,那么永远返回true,因为List系列是允许元素重复的
            //细节2:如果我们要往Set系列集合中添加数据,如果当前要添加的元素不存在,方法返回true,表示添加成功
            //                                  如果当前要添加的元素存在,方法返回false,表示添加失败
            //                                  因为Set系列的集合不允许重复。
            coll.add("aaa");
            coll.add("bbb");
            coll.add("ccc");
            System.out.println(coll);
    
            //2.清空
            /*coll.clear();
            System.out.println(coll);*/
    
            //3.删除
            //细节1:因为Colection里面定义的是共性的方法,所以此时不能通过索引进行删除,只能通过元素的对象进行删除
            //细节2:方法会有一个布尔类型的返回值,删除成功返回true,删除失败返回false
            //如果要删除的元素不存在,就会删除失败
            coll.remove("aaa");
            System.out.println(coll);
    
            //4.contains判断元素是否被包含
            //细节:底层是依赖equals方法进行判断是否存在的
            //所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法
            boolean result = coll.contains("aaa");
            System.out.println(result);
    
            //5.判断集合是否为空
            boolean result2 = coll.isEmpty();
            System.out.println(result2);//false
    
            //6.获取集合长度
            int size = coll.size();
            System.out.println(size);//2
        }
    }
    
    public class CollectionDemo02 {
        public static void main(String[] args) {
            //1.创建集合的对象
            Collection<Student> coll = new ArrayList<>();
    
            //2.创建三个学生对象
            Student s1 = new Student("zhangsan", 23);
            Student s2 = new Student("lisi", 24);
            Student s3 = new Student("wangwu", 25);
    
            //3.把学生对象添加到集合中
            coll.add(s1);
            coll.add(s2);
            coll.add(s3);
    
            //4.判断集合中某一个学生对象是否包含
            Student s4 = new Student("zhangsan", 23);
            //因为contains方法在底层依赖equals方法判断对象是否一致
            //如果存的是自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中的equals方法,依赖地址值进行判断
    
            //若果姓名和年龄都相同,就认为是同一个学生
            //所以,需要在自定义的Javabean类中,重写equals方法
            System.out.println(coll.contains(s4));
        }
    }
    
    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    
        public String toString() {
            return "Student{name = " + name + ", age = " + age + "}";
        }
    }
    
  2. Collection的遍历方式

    • 迭代器遍历

      • 迭代器不依赖索引

      • 迭代器在Java中的类是Iterator,迭代器是集合专用的遍历方式。

      • Collection集合获取迭代器

        方法名称说明
        Iterator iterator返回迭代器对象,默认指向当前集合的0索引
      • Iterator中的常用方法

        方法名称说明
        boolean hasNext()判断当前位置是否有元素,有元素返回true,没有元素返回false
        E next()获取当前位置的元素,并将迭代器对象移向下一个位置
        public class CollectionDemo03 {
            public static void main(String[] args) {
                /*
                    Collection系列集合三种通用的遍历方式
                        1.迭代器遍历
                        2.增强for循环
                        3.lambda表达式遍历
        
                    迭代器遍历相关的三个方法:
                        Iterator<E> iterator(): 获取一个迭代器对象
                        boolean hasNext():      判断当前指向的位置是否元素
                        E next():               获取当前指向的元素并移动指针
                 */
        
                //1.创建集合并添加元素
                Collection<String> coll = new ArrayList<>();
                coll.add("aaa");
                coll.add("bbb");
                coll.add("ccc");
                coll.add("ddd");
        
                //2.获取迭代器对象
                //迭代器就好比是一个箭头,默认指向集合的0索引处
                Iterator<String> it = coll.iterator();
                //3,利用循环不断地去获取集合中的每一个元素
                while(it.hasNext()) {
                    //4.next方法的两件事情:获取元素并移动指针
                    String str = it.next();
                    System.out.println(str);
                }
            }
        }
        
      • 细节注意点:

        (1)报错NoSuchElementException

        (2)迭代器遍历完毕,指针不会复位

        (3)循环中只能用一次next方法

        (4)迭代器遍历时,不能用集合的方法进行增加或者删除

        public class CollectionDemo04 {
            public static void main(String[] args) {
                /*
                    迭代器的细节注意点:
                        1.报错NoSuchElementException
                        2.迭代器遍历完毕,指针不会复位
                        3.循环中只能用一次next方法
                        4.迭代器遍历时,不能用集合的方法进行增加或者删除
                 */
        
                //1.创建集合并添加元素
                Collection<String> coll = new ArrayList<>();
                coll.add("aaa");
                coll.add("bbb");
                coll.add("ccc");
                coll.add("ddd");
        
                //2.获取迭代器对象
                //迭代器就好比是一个箭头,默认指向集合的0索引处
                Iterator<String> it = coll.iterator();
                //3,利用循环不断地去获取集合中的每一个元素
                while(it.hasNext()) {
                    //4.next方法的两件事情:获取元素并移动指针
                    String str = it.next();
                    System.out.println(str);
                }
        
                //当上面的循环结束之后,迭代器的指针已经指向了最后没有这个元素的位置
                //System.out.println(it.next());//NoSuchElementException
        
                //迭代器遍历完毕,指针不会复位
                System.out.println(it.hasNext());//false
        
                //如果要第二次继续遍历集合,只能再次获取一个新的迭代器对象
                Iterator<String> it2 = coll.iterator();
                while (it2.hasNext()) {
                    String str = it2.next();
                    System.out.println(str);
                }
            }
        }
        
        public class CollectionDemo05 {
            public static void main(String[] args) {
                /*
                    迭代器的细节注意点:
                        1.报错NoSuchElementException
                        2.迭代器遍历完毕,指针不会复位
                        3.循环中只能用一次next方法
                        4.迭代器遍历时,不能用集合的方法进行增加或者删除
                            如果实在要删除,那么可以用迭代器提供的remove方法进行删除
                            如果要添加,暂时没有办法
                 */
        
                //1.创建集合并添加元素
                Collection<String> coll = new ArrayList<>();
                coll.add("aaa");
                coll.add("bbb");
                coll.add("ccc");
                coll.add("ddd");
                coll.add("eee");
        
                //2.获取迭代器对象
                //迭代器就好比是一个箭头,默认指向集合的0索引处
                Iterator<String> it = coll.iterator();
                //3,利用循环不断地去获取集合中的每一个元素
                while(it.hasNext()) {
                    //4.next方法的两件事情:获取元素并移动指针
                    String str = it.next();
        
                    if("bbb".equals(str)) {
                        //coll.remove("bbb");
                        it.remove();
                    }
                }
                //System.out.println(coll);//ConcurrentModificationException
                System.out.println(coll);//[aaa, ccc, ddd, eee]
            }
        }
        
    • 增强for遍历

      • 增强for的底层就是迭代器,为了简化迭代器的代码书写的

      • 它是JDK5之后出现的,其内部原理就是一个Iterator迭代器

      • 所有的单列集合和数组才能用增强for进行遍历

      • 格式

        for(元素的数据类型 变量名:数组或集合) {
            //
        }
        

        例如:

        for(String s : list) {
            System.out.println(s);
        }
        
        public class CollectionDemo06 {
            public static void main(String[] args) {
                /*
                    Collection系列集合三种通用的遍历方式
                        1.迭代器遍历
                        2.增强for循环
                        3.lambda表达式遍历
        
                        增强for格式:
                            for(数据类型 变量名 : 集合/数组) {
                                //
                            }
                            快速生成方式:
                            集合的名字+for回车
                 */
        
                //1.创建集合并添加元素
                Collection<String> coll = new ArrayList<>();
                coll.add("zhangsan");
                coll.add("lisi");
                coll.add("wangwu");
        
                //2.利用增强for循环进行遍历
                //注意点:
                //s其实就是一个第三方变量,在循环的过程中依次表示集合中的每一个数据
                for(String s : coll) {
                    System.out.println(s);
                }
        
            }
        }
        
      • 增强for的细节:

        (1)修改增强for中的变量,不会改变按集合中原本的数据

        for(String s : list) {
            s = "q";
        }
        
    • Lambda表达式遍历

      得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。

      • 方法名称说明
        default void forEach(Consumer<? super T> action):结合lambda遍历集合
        public class CollectionDemo07 {
            public static void main(String[] args) {
                /*
                    Collection系列集合三种通用的遍历方式
                        1.迭代器遍历
                        2.增强for循环
                        3.lambda表达式遍历
        
                        lambda表达式遍历
                            default void forEach(Consumer<? super T> action):
                 */
        
                //1.创建集合并添加元素
                Collection<String> coll = new ArrayList<>();
                coll.add("zhangsan");
                coll.add("lisi");
                coll.add("wangwu");
                //2.利用匿名内部类的形式
                //底层原理:
                //其实也会自己遍历集合,依次得到每一个元素
                //把得到的每一个元素,传递给下面的accept方法
                //s依次表示集合中的每一个数据
                /*coll.forEach(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        System.out.println(s);
                    }
                });*/
        
                //lambda表达式
                //()->{}
                coll.forEach(s -> System.out.println(s));
            }
        }
        

List集合

  1. Lits集合的特有方法

    • Collection的方法List都继承了

    • List集合因为有索引,所以多了很多索引操作的方法

    • 常用方法

      方法名称说明
      void add(int index,E element)在此集合中的指定位置插入指定的元素
      E remove(int index)删除指定索引处的元素,返回被删除的元素
      E set(int index,E element)修改指定索引处的元素,返回被修改的元素
      E get(int index)返回指定索引处的元素
      public class ListDemo01 {
          public static void main(String[] args) {
              /*
                  List系列集合独有的方法:
                      void add(int index,E element)  在此集合中的指定位置插入指定的元素
                      E remove(int index)            删除指定索引处的元素,返回被删除的元素
                      E set(int index,E element)     修改指定索引处的元素,返回被修改的元素
                      E get(int index)               返回指定索引处的元素
               */
      
              //1.创建一个集合
              List<String> list = new ArrayList<>();
      
              //2.添加元素
              list.add("aaa");
              list.add("bbb");
              list.add("ccc");
      
              //void add(int index,E element)  在此集合中的指定位置插入指定的元素
              //细节:原来索引的元素会依次往后移
              //list.add(1,"QQQ");
      
              //E remove(int index)            删除指定索引处的元素,返回被删除的元素
              //String remove = list.remove(0);
              //System.out.println(remove);
      
              //E set(int index,E element)     修改指定索引处的元素,返回被修改的元素
              //String result = list.set(0, "QQQ");
              //System.out.println(result);
      
              //E get(int index)               返回指定索引处的元素
              String s = list.get(0);
              System.out.println(s);
      
              //3.打印集合
              System.out.println(list);
          }
      }
      
      public class ListDemo02 {
          public static void main(String[] args) {
              //List系列集合中的两个删除的方法
              //1.直接删除元素
              //2.通过索引进行删除
      
              //1.创建集合并添加元素
              List<Integer> list = new ArrayList<>();
      
              list.add(1);
              list.add(2);
              list.add(3);
      
              //2.删除元素
              //请问:此时删除的是1这个元素,还是1索引上的元素?(index)
              //因为在调用方法的时候,如果方法出现了重载现象
              //优先调用,实参跟形参类型一致的那个方法
              //list.remove(1);
      
              //手动装箱,手动把基本数据类型的1,变成Integer类型
              Integer i = Integer.valueOf(1);
              list.remove(i);
      
              System.out.println(list);
          }
      }
      
  2. List集合的遍历方式

    • 迭代器遍历
    • 列表迭代器遍历(独有)
    • 增强for遍历
    • Lambda表达式遍历
    • 普通for循环(因为Lits集合存在索引)
    public class ListDemo03 {
        public static void main(String[] args) {
            /*
                List系列集合的五种遍历方式:
                    1.迭代器遍历
                    2.列表迭代器遍历(独有)
                    3.增强for遍历
                    4.Lambda表达式遍历
                    5.普通for循环(因为Lits集合存在索引)
             */
    
            //创建集合并添加元素
            List<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
    
            //1.迭代器
            /*Iterator<String> it = list.iterator();
            while(it.hasNext()) {
                String str = it.next();
                System.out.println(str);
            }*/
    
            //2.增强for
            //下面的变量s,其实就是一个第三方的变量而已
            //在循环的过程中,依次表示集合中的每一个元素
            /*for (String s : list) {
                System.out.println(s);
            }*/
    
            //3.lambda表达式
            //forEach方法的底层其实就是一个循环遍历,依次得到集合中的每一个元素
            //并把每一个元素传递给下面的accept方法
            //accept方法的形参s,依次表示集合中的每一个元素
            //list.forEach(s -> System.out.println(s));
    
            //4.普通for循环
            //size方法跟get方法还有循环结合的方式,利用索引获取到集合中的每一个元素
            /*for (int i = 0; i < list.size(); i++) {
                //i:依次表示集合中的每一个索引
                String s = list.get(i);
                System.out.println(s);
            }*/
    
            //5.列表迭代器
            //获取一个列表迭代器的对象,里面的指针默认也是指向0索引的
    
            //额外添加了一个方法:在遍历的过程中,可以添加元素
            ListIterator<String> it = list.listIterator();
            while(it.hasNext()) {
                String str = it.next();
                if("bbb".equals(str)) {
                    //qqq
                    it.add("qqq");
                }
            }
            System.out.println(list);
        }
    }
    
  3. 五种遍历方式对比

    • 迭代器遍历:在遍历的过程中需要删除元素
    • 列表迭代器:在遍历的过程中需要添加元素
    • 增强for遍历+Lambda表达式:仅仅想遍历
    • 普通for:如果遍历的时候想操作索引,可以用普通for

数据结构

  1. 什么是数据结构呢?

    答:

    计算机底层存储、组织数据的方式,是指数据相互之间以什么方式排列在一起的。

    数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。

    一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。

    (1,每种数据结构长什么样子?2,如何添加数据?3,如何删除数据?)

  2. 常见的数据结构

    • 队列
    • 数组
    • 链表
    • 二叉树
    • 二叉查找树
    • 平衡二叉树
    • 红黑树

ArrayList集合

ArrayList集合底层原理

  • 利用空参创建的集合,在底层创建一个默认长度为0的数组
  • 添加第一个元素时,底层会创建一个新的长度为10的数组
  • 存满时,会扩容1.5倍
  • 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

LinkedList集合

  • 底层数据结构是双向链表,查询慢,增删快,但是如果操作的是首尾元素,速度也是极快的。

  • LinkedList本身多了很多直接操作首尾元素的特有API。

  • 特有方法

    特有方法说明
    public void addFirst(E e)在该列表开头插入指定的元素
    public void addLast(E e)将指定的元素追加到此列表的末尾
    public E getFirst()返回此列表中的第一个元素
    public E getLast()返回此列表中的最后一个元素
    public E removeFirst()从此列表中删除并返回第一个元素
    public E removeLast()从此列表中删除并返回最后一个元素

泛型深入

  1. 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。

  2. 泛型的格式:<数据类型>

  3. 注意:泛型只能支持引用数据类型。

  4. 泛型的好处:

    • 统一数据类型
    • 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
  5. 扩展知识点:Java中的泛型是伪泛型

  6. 泛型的细节:

    • 泛型中不能写基本数据类型
    • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
    • 如果不写泛型,类型默认是Object
    public class GenericsDemo01 {
        public static void main(String[] args) {
            //没有泛型的时候,集合如何存储数据
            //结论:
            //如果没有给集合指定类型,默认所有的数据类型都是Object类型
            //此时可以往集合添加任意的数据类型
            //带来一个坏处:在获取数据的时候,无法使用它的特有行为
    
            //此时推出了泛型,可以在添加数据的时候就把类型进行统一
            //而且在获取数据的时候,也省得强转了,非常方便
    
            //1.创建集合的对象
            ArrayList list = new ArrayList();
    
            //2.添加数据
            list.add(123);
            list.add("abc");
            list.add(new Student("zhangsan",123));
    
            //3.遍历集合获取里面的每一个数据
            Iterator it = list.iterator();
            while(it.hasNext()) {
                Object obj = it.next();
                //多态的弊端是不能访问子类的特有功能
                //obj.length();
                System.out.println(obj);
            }
        }
    }
    
  7. 泛型可以在很多地方进行定义

    (写在)类后面——泛型类

    (写在)方法上面——泛型方法

    (写在)接口后面——泛型接口

  8. 泛型类

    使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

    //格式:
    修饰符 class 类名<类型> {
        //
    }
    
    //举例:
    public class ArrayList<E> {
        //创建该类对象时,E就确定类型
    }
    //此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T、E、K、V等
    
    /**
     *      当编写一个类时,如果不确定类型,那么这个类就可以定义为泛型类
     */
    public class MyArrayList<E> {
        Object[] obj = new Object[10];
        int size;
    
        /**
         * E:表示是不确定的类型,该类型在类名后面已经定义过了
         * e:形参的名字,变量名
         */
        public boolean add(E e) {
            obj[size] = e;
            size++;
            return true;
        }
    
        public E get(int index) {
            return (E)obj[index];
        }
    
        @Override
        public String toString() {
            return Arrays.toString(obj);
        }
    }
    
    public class GenericsDemo02 {
        public static void main(String[] args) {
            /*MyArrayList<String> list = new MyArrayList<>();
    
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
    
            System.out.println(list);*/
    
            MyArrayList<Integer> list = new MyArrayList<>();
    
            list.add(123);
            list.add(456);
            list.add(789);
    
            int i = list.get(0);
            System.out.println(i);
    
            System.out.println(list);
        }
    }
    
  9. 泛型方法

    方法中形参类型不确定时,可以使用类名后面定义的泛型

    public class MyArrayList {
        public <E> boolean add(E e) {
            obj[size] = e;
            size++;
            return true;
        }
    }
    
    //格式
    修饰符 <类型> 返回值类型 方法名(类型 变量名) {
        //
    }
    //举例
    public <T> void show(T t) {
        //此处T可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成:T、E、K、V等
    }
    

    泛型方法的练习

    定义一个工具类:ListUtil

    类中定义一个静态方法addAll,用来添加多个集合的元素。

    public class ListUtil {
        private ListUtil() {}
    
        //类中定义一个静态方法addAll,用来添加多个集合的元素
    
        /**
         *  参数一:集合
         *  参数二~最后:要添加的元素
         */
        public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4) {
            list.add(e1);
            list.add(e2);
            list.add(e3);
            list.add(e4);
        }
    
        public static<E> void addAll(ArrayList<E> list,E...e) {
            for (E e1 : e) {
                list.add(e1);
            }
        }
    
        public void show() {
            System.out.println("谢谢你");
        }
    }
    
    /**
     * 定义一个工具类:ListUtil
     * 类中定义一个静态方法addAll,用来添加多个集合的元素。
     */
    public class GenericsDemo03 {
        public static void main(String[] args) {
            ArrayList<String> list = new ArrayList<>();
            ListUtil.addAll(list,"aaa","bbb","ccc","ddd");
            System.out.println(list);
    
            ArrayList<Integer> list2 = new ArrayList<>();
            ListUtil.addAll(list2,1,2);
            System.out.println(list2);
        }
    }
    
  10. 泛型接口

    //格式
    修饰符 interface 接口名<类型> {
        //
    }
    //举例:
    public interface List<E> {
        //
    }
    

    重点:如何使用一个带泛型的接口

    方式1:实现类给出具体类型

    方式2:实现类延续泛型,创建对象时再确定

    public class GenericsDemo04 {
        public static void main(String[] args) {
            /*
                泛型接口的两种使用方式:
                    方式1:实现类给出具体类型
                    方式2:实现类延续泛型,创建实现类对象时再确定
             */
    
            //方式1:实现类给出具体类型
            /*MyArrayList2 list = new MyArrayList2();
            list.add("Hello");*/
            MyArrayList3<String> list = new MyArrayList3<>();
            list.add("World");
        }
    }
    
    public class MyArrayList2 implements List<String> {//实现类给出具体类型
        @Override
        public int size() {
            return 0;
        }
    
        @Override
        public boolean isEmpty() {
            return false;
        }
    
        @Override
        public boolean contains(Object o) {
            return false;
        }
    
        @Override
        public Iterator<String> iterator() {
            return null;
        }
    
        @Override
        public Object[] toArray() {
            return new Object[0];
        }
    
        @Override
        public <T> T[] toArray(T[] a) {
            return null;
        }
    
        @Override
        public boolean add(String s) {
            return false;
        }
    
        @Override
        public boolean remove(Object o) {
            return false;
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public boolean addAll(Collection<? extends String> c) {
            return false;
        }
    
        @Override
        public boolean addAll(int index, Collection<? extends String> c) {
            return false;
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public void clear() {
    
        }
    
        @Override
        public String get(int index) {
            return null;
        }
    
        @Override
        public String set(int index, String element) {
            return null;
        }
    
        @Override
        public void add(int index, String element) {
    
        }
    
        @Override
        public String remove(int index) {
            return null;
        }
    
        @Override
        public int indexOf(Object o) {
            return 0;
        }
    
        @Override
        public int lastIndexOf(Object o) {
            return 0;
        }
    
        @Override
        public ListIterator<String> listIterator() {
            return null;
        }
    
        @Override
        public ListIterator<String> listIterator(int index) {
            return null;
        }
    
        @Override
        public List<String> subList(int fromIndex, int toIndex) {
            return null;
        }
    }
    
    public class MyArrayList3<E> implements List<E> {
        @Override
        public int size() {
            return 0;
        }
    
        @Override
        public boolean isEmpty() {
            return false;
        }
    
        @Override
        public boolean contains(Object o) {
            return false;
        }
    
        @Override
        public Iterator<E> iterator() {
            return null;
        }
    
        @Override
        public Object[] toArray() {
            return new Object[0];
        }
    
        @Override
        public <T> T[] toArray(T[] a) {
            return null;
        }
    
        @Override
        public boolean add(E e) {
            return false;
        }
    
        @Override
        public boolean remove(Object o) {
            return false;
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
            return false;
        }
    
        @Override
        public boolean addAll(int index, Collection<? extends E> c) {
            return false;
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return false;
        }
    
        @Override
        public void clear() {
    
        }
    
        @Override
        public E get(int index) {
            return null;
        }
    
        @Override
        public E set(int index, E element) {
            return null;
        }
    
        @Override
        public void add(int index, E element) {
    
        }
    
        @Override
        public E remove(int index) {
            return null;
        }
    
        @Override
        public int indexOf(Object o) {
            return 0;
        }
    
        @Override
        public int lastIndexOf(Object o) {
            return 0;
        }
    
        @Override
        public ListIterator<E> listIterator() {
            return null;
        }
    
        @Override
        public ListIterator<E> listIterator(int index) {
            return null;
        }
    
        @Override
        public List<E> subList(int fromIndex, int toIndex) {
            return null;
        }//实现类延续泛型,创建实现类对象时再确定
    }
    
  11. 泛型的继承和通配符

    • 泛型不具备继承性,但是数据具备继承性
    public class GenericsDemo05 {
        public static void main(String[] args) {
            /*
                泛型不具备继承性,但是数据具备继承性
             */
    
            //创建集合对象
            ArrayList<Ye> list1 = new ArrayList<>();
            ArrayList<Fu> list2 = new ArrayList<>();
            ArrayList<Zi> list3 = new ArrayList<>();
    
            //调用method方法
            method(list1);
            //method(list2);//报错
            //method(list3);//报错
    
            //数据具备继承性
            list1.add(new Ye());
            list1.add(new Fu());
            list1.add(new Zi());
        }
    
        /**
         * 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
         * @param list
         */
        public static void method(ArrayList<Ye> list) {
    
        }
    }
    
    class Ye{}
    class Fu extends Ye{}
    class Zi extends Fu{}
    
    public class GenericsDemo06 {
        public static void main(String[] args) {
            /**
             * 需求:
             *      定义一个方法,形参是一个集合,但是集合中的数据类型不确定
             */
    
            //创建集合对象
            ArrayList<Ye> list1 = new ArrayList<>();
            ArrayList<Fu> list2 = new ArrayList<>();
            ArrayList<Zi> list3 = new ArrayList<>();
    
            //调用method方法
            method(list1);
            method(list2);
            method(list3);
        }
    
        /**
         * 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
         * 弊端:
         *      利用泛型方法有一个小弊端,此时它可以接受任意的数据类型。
         *      Ye Fu Zi    Student
         *
         *      希望:本方法虽然不确定类型,但是以后希望只能传递Ye Fu Zi
         *
         *      此时我们就可以使用泛型的通配符:
         *      ?也表示不确定的类型
         *      它可以进行类型的限定
         *      ? extends E:表示可以传递E或者E所有的子类类型
         *      ? super E:表示可以传递E或者E所有的父类类型
         *
         *      应用场景:
         *          1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
         *          2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符
         *      泛型的通配符:
         *          关键点:可以限定类型的范围
         */
        public static<E> void method(ArrayList<? super Zi> list) {
    
        }
    }
    
  12. 练习

    public abstract class Animal {
        private String name;
        private int age;
    
        public abstract void eat();
    
        public Animal() {
        }
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return "Animal{name = " + name + ", age = " + age + "}";
        }
    }
    
    public abstract class Cat extends Animal{
        public Cat(String name, int age) {
            super(name, age);
        }
        //1.继承抽象类,重写里面所有的抽象类
        //2.本身Cat也是一个抽象的,让Cat的子类再重写方法
    
        //此时采取第二种处理方案
        //因为猫的两个子类eat的方法体还是不一样的
    }
    
    public abstract class Dog extends Animal{
        public Dog(String name, int age) {
            super(name, age);
        }
    }
    
    //波斯猫
    public class PersianCat extends Cat{
        public PersianCat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫作" + this.getName() + "的," + this.getAge() + "岁的波斯猫,正在吃小饼干");
        }
    }
    
    //狸花猫
    public class DragonLi extends Cat{
        public DragonLi(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫作" + this.getName() + "的," + this.getAge() + "岁的狸花猫,正在吃小鱼干");
        }
    }
    
    //泰迪
    public class Teddy extends Dog{
        public Teddy(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫作" + this.getName() + "的," + this.getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");
        }
    }
    
    //哈士奇
    public class SiberianHusky extends Dog{
        public SiberianHusky(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫作" + this.getName() + "的," + this.getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");
        }
    }
    
    public class GenericsDemoTest {
        public static void main(String[] args) {
            /*
                需求:
                    定义一个继承结构:
                                       动物
                            |                      |
                            猫                     狗
                       |          |           |          |
                     波斯猫      狸花猫        泰迪        哈士奇
    
                     属性:名字、年龄
                     行为:吃东西
                        方法体打印:一只叫作xxx的,x岁的波斯猫,正在吃小饼干
                        方法体打印:一只叫作xxx的,x岁的狸花猫,正在吃小鱼干
                        方法体打印:一只叫作xxx的,x岁的泰迪,正在吃骨头,边吃边蹭
                        方法体打印:一只叫作xxx的,x岁的哈士奇,正在吃骨头,边吃边拆家
    
                     测试类中定义一个方法用于饲养动物
                        public static void keepPet(ArrayList<???> list) {
                            //遍历集合,调用动物的eat方法
                        }
                     需求1:该方法能养所有品种的猫,但是不能养狗
                     需求2:该方法能养所有品种的狗,但是不能养猫
                     需求3:该方法能养所有的动物,但是不能传递其他类型
    
             */
    
            //创建集合添加对象
            ArrayList<PersianCat> cat1 = new ArrayList<>();
            ArrayList<DragonLi> cat2 = new ArrayList<>();
            ArrayList<Teddy> dog1 = new ArrayList<>();
            ArrayList<SiberianHusky> dog2 = new ArrayList<>();
    
            cat1.add(new PersianCat("球球", 1));
            cat2.add(new DragonLi("圆圆", 2));
            dog1.add(new Teddy("来福",4));
            dog2.add(new SiberianHusky("旺财",3));
    
    
            keepPet(cat1);
            keepPet(cat2);
            keepPet(dog1);
            keepPet(dog2);
        }
    
        //需求1:该方法能养所有品种的猫,但是不能养狗
        /*public static void keepPet(ArrayList<? extends Cat> List) {
            //遍历集合,调用动物的eat方法
        }*/
    
        //需求2:该方法能养所有品种的狗,但是不能养猫
        /*public static void keepPet(ArrayList<? extends Dog> List) {
            //遍历集合,调用动物的eat方法
        }*/
    
        //需求3:该方法能养所有的动物,但是不能传递其他类型
        public static void keepPet(ArrayList<? extends Animal> List) {
            //遍历集合,调用动物的eat方法
            for (Animal animal : List) {
                animal.eat();
            }
        }
    }
    

Set集合

练习:存储字符串并遍历

利用Set系列的集合,添加字符串,并使用多种方式遍历

(1)迭代器

(2)增强for

(3)Lambda表达式

public class SetDemo01 {
    public static void main(String[] args) {
        /*
            利用Set系列的集合,添加字符串,并使用多种方式遍历
            (1)迭代器
            (2)增强for
            (3)Lambda表达式
         */

        //1.创建一个Set集合的对象
        Set<String> s = new HashSet<>();

        //2.添加元素
        //如果当前元素是第一次添加,那么可以添加成功,返回true
        //如果当前元素是第二次添加,那么添加失败,返回false
        boolean r1 = s.add("zhangsan");
        boolean r2 = s.add("zhangsan");
        s.add("lisi");
        s.add("wangwu");

        System.out.println(r1);//true
        System.out.println(r2);//false

        //3.打印集合
        //无序
        //System.out.println(s);//[zhangsan]
        //System.out.println(s);//[lisi, zhangsan, wangwu]

        //迭代器遍历
        /*Iterator<String> it = s.iterator();
        while(it.hasNext()) {
            String str = it.next();
            System.out.println(str);
        }*/

        //增强for
        /*for (String s1 : s) {
            System.out.println(s1);
        }*/

        //lambda表达式
        s.forEach(str -> System.out.println(str));
    }
}

HashSet

  1. HashSet底层原理

    • HashSet集合底层采取哈希表存储数据
    • 哈希表是一种对于增删改查数据性能都较好的数据
  2. 哈希表组成

    • JDK8之前:数组+链表
    • JDK8之后:数组+链表+红黑树
  3. 哈希值

    对象的整数表现形式。

    • 根据hashCode方法算出来的int类型的整数
    • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
    • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
  4. 对象的哈希值特点

    • 如果没有重写hashCode方法,不同对象计算出来的哈希值是不同的。
    • 如果已经重写hashCode方法,不同的对象只要属性值相同,计算出来的哈希值就是一样的。
    • 在小部分情况下,不同的属性值或者不同的地址计算出来的哈希值也有可能是一样的。(哈希碰撞)
    public class HashSetDemo01 {
        public static void main(String[] args) {
            /*
                哈希值:
                    对象的整数表现形式
                    1.如果没有重写hashCode方法,不同对象计算出来的哈希值是不同的。
                    2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算出来的哈希值就是一样的。
                    3.在小部分情况下,不同的属性值或者不同的地址计算出来的哈希值也有可能是一样的。(哈希碰撞)
    
             */
    
            //1.创建对象
            Student s1 = new Student("zhangsan", 23);
            Student s2 = new Student("zhangsan", 23);
    
            //2.如果没有重写hashCode方法,不同对象计算出来的哈希值是不同的。
            //如果已经重写hashCode方法,不同的对象只要属性值相同,计算出来的哈希值就是一样的。
            //System.out.println(s1.hashCode());//460141958(重写之前)
            //System.out.println(s2.hashCode());//1163157884(重写之前)
            System.out.println(s1.hashCode());//-1461067292(重写之后)
            System.out.println(s2.hashCode());//-1461067292(重写之后)
    
            //在小部分情况下,不同的属性值或者不同的地址计算出来的哈希值也有可能是一样的。(哈希碰撞)
            System.out.println("abc".hashCode());//96354
            System.out.println("acD".hashCode());//96354
        }
    }
    
  5. HashSet JDK8以前底层原理

    • 创建一个默认长度16,默认加载因子为0.75的数组,数组名table

      HashSet<String> hm = new HashSet<>();
      
    • 根据元素的哈希值跟数组的长度计算出应存入的位置

      int index = (数组长度 - 1) & 哈希值
      
    • 判断当前位置是否是null,如果是null直接存入

    • 如果位置不为null,表示有元素,则调用equals方法比较属性值

    • 属性值一样——不存/属性值不一样——存入数组,形成链表

      JDK8以前:新元素存入数组,老元素挂在新元素下面

      JDK8以后:新元素直接挂在老元素下面

    • JDK8以后,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树

    • 如果集合中存储的是自定义对象,必须要重写hashCode和equals方法

  6. HashSet的三个问题

    • HashSet为什么存和取的顺序不一样?
    • HashSet为什么没有索引?
    • HashSet是利用什么机制保证数据去重的?(HashCode和equals方法)
  7. 案例:利用HashSet集合去除重复元素

    需求:创建一个存储学生对象的集合,存储多个学生对象。

    使用程序实现在控制台遍历该集合。

    要求:学生对象的成员变量值相同,我们就认为是同一个对象

    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Student student = (Student) o;
            return age == student.age && Objects.equals(name, student.name);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    
        public String toString() {
            return "Student{name = " + name + ", age = " + age + "}";
        }
    }
    
    public class HashSetDemo02 {
        public static void main(String[] args) {
            /*
                需求:创建一个存储学生对象的集合,存储多个学生对象。
                使用程序实现在控制台遍历该集合。
                要求:学生对象的成员变量值相同,我们就认为是同一个对象
             */
    
            //1.创建四个学生对象
            Student s1 = new Student("zhangsan", 21);
            Student s2 = new Student("lisi", 23);
            Student s3 = new Student("wangwu", 22);
            Student s4 = new Student("zhangsan", 21);
    
            //2.创建集合用来添加学生
            HashSet<Student> hs = new HashSet<>();
    
            //3.添加元素
            System.out.println(hs.add(s1));
            System.out.println(hs.add(s2));
            System.out.println(hs.add(s3));
            System.out.println(hs.add(s4));
    
            //4.打印集合
            System.out.println(hs);
        }
    }
    

LinkedHashSet

  1. LinkedHashSet底层原理

    • 有序、不重复、无索引
    • 这里的有序指的是保证存储和取出的顺序一致
    • 原理:底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
    public class LinkedHashSetDemo {
        public static void main(String[] args) {
            //1.创建四个学生对象
            Student s1 = new Student("zhangsan", 21);
            Student s2 = new Student("lisi", 23);
            Student s3 = new Student("wangwu", 22);
            Student s4 = new Student("zhangsan", 21);
    
            //2.创建集合用来添加学生
            LinkedHashSet<Student> lhs = new LinkedHashSet<>();
    
            //3.添加元素
            System.out.println(lhs.add(s3));
            System.out.println(lhs.add(s2));
            System.out.println(lhs.add(s1));
            System.out.println(lhs.add(s4));
    
            //4.打印集合
            System.out.println(lhs);
        }
    }
    

TreeSet

  1. TreeSet的特点

    • 不重复、无索引、可排序
    • 可排序:按照元素的默认规则(由小到大)排序
    • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。
  2. 练习:TreeSet对象排序练习题

    需求:利用TreeSet存储整数并进行排序

    public class TreeSetDemo01 {
        public static void main(String[] args) {
            /*
                利用TreeSet存储整数并进行排序
             */
    
            //1.创建TreeSet集合对象
            TreeSet<Integer> ts = new TreeSet<>();
    
            //2.添加元素
            ts.add(4);
            ts.add(5);
            ts.add(1);
            ts.add(3);
            ts.add(2);
    
            //3.打印集合
            //System.out.println(ts);//[1, 2, 3, 4, 5]
    
            //4.遍历集合(三种遍历)
            //迭代器
            /*Iterator<Integer> it = ts.iterator();
            while(it.hasNext()) {
                Integer i = it.next();
                System.out.println(i);
            }*/
    
            //增强for
            /*for (Integer t : ts) {
                System.out.println(t);
            }*/
    
            //lambda表达式
            ts.forEach(integer -> System.out.println(integer));
        }
    }
    
  3. TreeSet集合默认的规则

    • 对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序
    • 对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序
  4. TreeSet对象排序练习题

    需求:创建TreeSet集合,并添加3个学生对象

    学生对象属性:姓名、年龄

    要求按照学生的年龄进行排序

    同年龄按照姓名字母排列(按不考虑中文)

    同姓名,同年龄认为是同一个人

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        public String toString() {
            return "Student{name = " + name + ", age = " + age + "}";
        }
    
        @Override
        //this:表示当前要添加的元素
        //o:表示已经在红黑树存在的元素
    
        //返回值:
        //负数:表示当前要添加的元素是小的,存左边
        //正数:表示当前要添加的元素是大的,存右边
        //0:表示当前要添加的元素已存在,舍弃
        public int compareTo(Student o) {
            System.out.println("-------------");
            System.out.println("this:" + this);
            System.out.println("o:" + o);
            //指定排序规则
            //只看年龄,想要按照年龄的升序进行排序
            return this.getAge() - o.getAge();
        }
    }
    
    public class TreeSetDemo02 {
        public static void main(String[] args) {
            /*
                需求:创建TreeSet集合,并添加3个学生对象
                学生对象属性:姓名、年龄
                要求按照学生的年龄进行排序
                同年龄按照姓名字母排列(按不考虑中文)
                同姓名,同年龄认为是同一个人
    
                方式一:
                    默认排序/自然排序
                    Student实现Comparable接口,重写里面的抽象方法,再指定比较规则
             */
    
            //1.创建三个学生对象
            Student s1 = new Student("zhangsan", 23);
            Student s2 = new Student("lisi", 24);
            Student s3 = new Student("wangwu", 25);
    
            //2.创建集合对象
            TreeSet<Student> ts = new TreeSet<>();
    
            //3.添加元素
            ts.add(s1);
            ts.add(s2);
            ts.add(s3);
    
            //4.打印集合
            System.out.println(ts);
        }
    }
    
  5. TreeSet的两种比较方式

    • 方式一:默认排序/自然排序:Javabean类实现Comparable接口指定比较规则。
    • 方式二:比较器排序:创建TreeSet对象的时候,传递比较器Comparable制定规则

    使用原则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种

  6. 练习:TreeSet对象排序练习题

    需求:请自行选择比较器排序和自然排序两种方式

    要求:存入四个字符串,“c”,“ab”,“df”,“qwer” 按照长度排序,如果一样长则按照首字母排序

    public class TreeSetDemo03 {
        public static void main(String[] args) {
            /*
                需求:请自行选择比较器排序和自然排序两种方式
                要求:存入四个字符串,"c","ab","df","qwer" 按照长度排序,如果一样长则按照首字母排序
    
                采取第二种排序方式:比较器排序
             */
    
            //1.创建集合
            //o1:表示当前要添加的元素
            //o2:表示已经在红黑树存在的元素
            //返回值规则跟之前是一样的
            //匿名内部类
            /*TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    //按照长度排序
                    int i = o1.length() - o2.length();
                    //如果一样长则按照首字母排序
                    i = i == 0 ? o1.compareTo(o2) : i;
                    return i;
                }
            });*/
    
            //lambda表达式
            TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
                    //按照长度排序
                    int i = o1.length() - o2.length();
                    //如果一样长则按照首字母排序
                    i = i == 0 ? o1.compareTo(o2) : i;
                    return i;
                }
            );
    
            //2.添加元素
            ts.add("c");
            ts.add("ab");
            ts.add("df");
            ts.add("qwer");
    
            //3.打印集合
            System.out.println(ts);
        }
    }
    
  7. 练习:TreeSet对象排序练习题

    需求:创建5个学生对象

    属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)

    按照总分从高到低输出到控制台

    如果总分一样,按照语文成绩排

    如果语文一样,按照数学成绩排

    如果数学成绩一样,按照英语成绩排

    如果英语成绩一样,按照年龄排

    如果年龄一样,按照姓名的字母顺序排

    如果都一样,认为是同一个学生,不存

    public class NewStudent implements Comparable<NewStudent>{
        //姓名
        private String name;
        //年龄
        private int age;
        //语文成绩
        private int chinese;
        //数学成绩
        private int math;
        //英语成绩
        private int english;
    
        public NewStudent() {
        }
    
        public NewStudent(String name, int age, int chinese, int math, int english) {
            this.name = name;
            this.age = age;
            this.chinese = chinese;
            this.math = math;
            this.english = english;
        }
    
        @Override
        /*按照总分从高到低输出到控制台
        如果总分一样,按照语文成绩排
        如果语文一样,按照数学成绩排
        如果数学成绩一样,按照英语成绩排
        如果英语成绩一样,按照年龄排
        如果年龄一样,按照姓名的字母顺序排
        如果都一样,认为是同一个学生,不存*/
        public int compareTo(NewStudent o) {
            int sum1 = this.getChinese() + this.getMath() + this.getEnglish();
            int sum2 = o.getChinese() + o.getMath() + o.getEnglish();
    
            //比较两者的总分
            int i = sum1 - sum2;
    
            //如果总分一样,按照语文成绩排
            i = i == 0 ? this.getChinese() - o.getChinese() : i;
            //如果语文一样,按照数学成绩排
            i = i == 0 ? this.getMath() - o.getMath() : i;
            //如果数学成绩一样,按照英语成绩排
            i = i == 0 ? this.getEnglish() - o.getEnglish() : i;
            //如果英语成绩一样,按照年龄排(可以省略不写)
            i = i == 0 ? this.getAge() - o.getAge() : i;
            // 如果年龄一样,按照姓名的字母顺序排
            i = i == 0 ? this.getName().compareTo(o.getName()) : i;
            return i;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        /**
         * 获取
         * @return chinese
         */
        public int getChinese() {
            return chinese;
        }
    
        /**
         * 设置
         * @param chinese
         */
        public void setChinese(int chinese) {
            this.chinese = chinese;
        }
    
        /**
         * 获取
         * @return math
         */
        public int getMath() {
            return math;
        }
    
        /**
         * 设置
         * @param math
         */
        public void setMath(int math) {
            this.math = math;
        }
    
        /**
         * 获取
         * @return english
         */
        public int getEnglish() {
            return english;
        }
    
        /**
         * 设置
         * @param english
         */
        public void setEnglish(int english) {
            this.english = english;
        }
    
        public String toString() {
            return "NewStudent{name = " + name + ", age = " + age + ", chinese = " + chinese + ", math = " + math + ", english = " + english + "}";
        }
    }
    
    public class TreeSetDemo04 {
        public static void main(String[] args) {
            /*
                需求:创建5个学生对象
                属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)
                按照总分从高到低输出到控制台
                如果总分一样,按照语文成绩排
                如果语文一样,按照数学成绩排
                如果数学成绩一样,按照英语成绩排
                如果英语成绩一样,按照年龄排
                如果年龄一样,按照姓名的字母顺序排
                如果都一样,认为是同一个学生,不存
    
                第一种:默认排序/自然排序
                第二种:比较器排序
    
                默认情况下,用第一种方式,如果第一种方式不能满足当前的需求,采取第二种方式
             */
    
            //1.创建学生对象
            NewStudent s1 = new NewStudent("zhangsan", 23, 90, 99, 50);
            NewStudent s2 = new NewStudent("lisi", 24, 90, 98, 50);
            NewStudent s3 = new NewStudent("wangwu", 25, 95, 100, 30);
            NewStudent s4 = new NewStudent("zhaoliu", 26, 60, 99, 70);
            NewStudent s5 = new NewStudent("qianqi", 26, 70, 80, 70);
    
            //2.创建集合
            //默认ArrayList
            //HashSet
            //TreeSet
            TreeSet<NewStudent> ts = new TreeSet<>();
    
            //3.添加元素
            ts.add(s1);
            ts.add(s2);
            ts.add(s3);
            ts.add(s4);
            ts.add(s5);
    
            //4.打印集合
            //System.out.println(ts);
            for (NewStudent t : ts) {
                System.out.println(t);
            }
        }
    }
    

Collention下各集合适用场景

  1. 如果想要集合中的元素可重复

    用ArrayList,基于数组的(用的最多)

  2. 如果想要集合中的元素可重复,而且当前的增删操作明显多于查询操作

    用LinkedList,基于链表的

  3. 如果想对集合中的元素去重

    用HashSet,基于哈希表的。(用的最多)

  4. 如果想对集合中的元素去重,而且保证存取顺序

    用LinkedHashSet,基于哈希表和双链表,效率低于HashSet

  5. 如果相对集合中的元素进行排序

    用TreeSet,基于红黑树,后续也可以用List集合实现排序

说明:

以上笔记学习是学习b站黑马程序员时记下的笔记,仅限于帮助理解学习,不做任何其他商业用途。

黑马程序员

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值