十三、集合进阶——单列集合 及 数据结构

单列集合 及 数据结构

  • 13.1 集合体系结构
    • 13.1.2 单列集合
      • 1. Collection
      • 2.Collection 的遍历方式
        • 迭代器遍历
        • 增强for遍历
        • Lambda表达式遍历
      • 3.List集合
        • List集合的特有方法
        • List集合的遍历方式
        • 五种遍历方式对比
      • 4.数据结构
        • 1).栈
        • 2).队列
        • 3)数组
        • 4)链表
        • 小结
        • 5)树
        • 6)二叉查找树
        • 7)平衡二叉树
          • 平衡二叉树旋转机制——左旋
          • 平衡二叉树旋转机制——右旋
          • 平衡二叉树需要旋转的四种情况
        • 8)红黑树
          • 添加节点的规则
      • 5.ArrayList集合
        • 1.ArrayList集合底层原理
        • 2.LinkedList集合
        • 3.迭代器底层源码解析
      • 6.泛型深入
        • 1)泛型概述
        • 2)泛型类
        • 3)泛型方法
        • 4)泛型接口
        • 5)泛型的继承和通配符
        • 总结
      • 7.Set系列集合
        • 1)HashSet
        • 2)LinkedHashSet
        • 3)TreeSet
      • 8.单列集合使用场景


13.1 集合体系结构

在这里插入图片描述
在这里插入图片描述

13.1.2 单列集合

在这里插入图片描述

在这里插入图片描述

  • List系列集合:添加的元素是有序、可重复、有索引。
  • Set系列集合:添加的元素是无序、不重复、无索引。

1. Collection

Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
在这里插入图片描述

public static void main(String[] args) {
        /*注意点:
        * Collection 是一个接口,我们不能直接创建他的对象。
        * 所以,在学习它的方法时,只能创建他实现类的对象
        * 实现类:ArrayList
        *
        * 目的:为了学习Collection接口里面的方法。*/

        Collection<String> coll = new ArrayList<>();

        //0.添加元素
        System.out.println("-------------0.添加元素-------------");
        /*细节1:如果要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。
        * 细节2:如果要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。
                                           * 如果当前要添加的元素已经存在,方法返回false,表示添加失败
                                           * 因为Set系列的集合不允许重复。*/
        coll.add("zhangsan");
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");

        System.out.println(coll); // [zhangsan, aaa, bbb, ccc]

        //1.清空
        System.out.println("-------------1.清空-------------");
//        coll.clear();
        System.out.println(coll); // []

        //2.删除
        //细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引删除,只能通过元素的对象进行删除。
        //细节2:方法会有一个返回值,删除成功返回true,删除失败返回false。
        System.out.println("-------------2.删除-------------");

        coll.remove("aaa");

        System.out.println(coll); // [zhangsan, bbb, ccc]

        //3.判断元素是否包含
        /*细节:底层是依赖equals方法进行判断是否存在的。
        * 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法*/
        System.out.println("-------------3.判断元素是否包含-------------");

        System.out.println(coll.contains("aaa")); //false
        System.out.println(coll.contains("bbb")); // true

        System.out.println("------------------------------------------");

        //4.判断是否为空
        System.out.println("-------------3.判断元素是否包含-------------");

        System.out.println(coll.isEmpty()); //false
        System.out.println("------------------------------------------");

        //5.获取集合的长度
        int size = coll.size();
        System.out.println(size); // 3
    }

Contains方法 细节

public static void main(String[] args) {
        //0.创建集合对象
        Collection<Student> coll = new ArrayList<>();

        //1.创建三个学生对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 25);
        Student s3 = new Student("wangwu", 26);

        //2.把学生对象添加到集合中
        coll.add(s1);
        coll.add(s2);
        coll.add(s3);

        //3.判断集合中某一个学生对象是否包含
        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中的类是 Iterrator ,迭代器是集合专用的遍历方式。
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        //0.创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("aaa");
        coll.add("bbb");
        coll.add("ccc");
        coll.add("ddd");

        //1.获取迭代器对象
        Iterator<String> it = coll.iterator();

        //2.利用循环不断的去获取集合中的每一个元素
        while (it.hasNext()) {
            //3.next方法的两件事情:获取元素并移动指针
            String str = it.next();
            System.out.println(str);
        }
    }

在这里插入图片描述
在这里插入图片描述

增强for遍历

在这里插入图片描述

public static void main(String[] args) {
        //增强for遍历
        //0.创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhangsan");
        coll.add("lisi");
        coll.add("wangwu");

        //1.利用增强for遍历
        for (String s : coll) {
            System.out.println(s);
        }
    }

在这里插入图片描述

Lambda表达式遍历

在这里插入图片描述

public static void main(String[] args) {
        //Lambda 表达式遍历
        //0.创建集合并添加元素
        Collection<String> coll = new ArrayList<>();
        coll.add("zhangsan");
        coll.add("lisi");
        coll.add("wangwu");

        //利用匿名内部类的形式
        /*底层原理:
         * 其实也会自己遍历集合,依次得到每一个元素
         * 把得到的每一个元素,传递给下面的accept方法
         * s 依次表示集合中的每一个的对象 */
        coll.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("--------------------------");
        //1.Lambda表达式遍历
        coll.forEach(s -> System.out.println(s) );
    }

在这里插入图片描述

3.List集合

在这里插入图片描述

List集合的特有方法

在这里插入图片描述

 public static void main(String[] args) {
        //0.创建一个集合
        List<String> list = new ArrayList<>();
        //1.添加元素
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        //打印集合
        System.out.println(list); // [aaa, bbb, ccc]

        System.out.println("-------------------------");

        //2.在指定位置插入指定的元素
        list.add(2, "zhangsan");

        System.out.println(list); // [aaa, bbb, zhangsan, ccc]

        System.out.println("-------------------------");

        //3.删除指定索引处的元素,返回被删除的元素
        /*在调用方法的时候,如果方法出现了重载现象
        * 优先调用,实参跟形参类型一致的那个方法。*/
        String remove = list.remove(2);
        System.out.println(remove); // zhangsan
        System.out.println(list); // [aaa, bbb, ccc]
        System.out.println("-------------------------");

        //4.修改指定索引处的元素,返回被修改的元素
        list.set(0,"狗剩");
        System.out.println(list); // [狗剩, bbb, ccc]
        System.out.println("-------------------------");

        //5.返回指定索引处的元素
        String s = list.get(1);
        System.out.println(s); // bbb
    }
List集合的遍历方式

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        //0.创建集合并添加元素
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

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

        System.out.println("------------------------");

        //2.增强for
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("------------------------");

        //3.Lambda 表达式
        //匿名内部类
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("-------------------------");
        list.forEach(s -> System.out.println(s));
        System.out.println("------------------------");

        //4.普通for循环
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("-------------------------");

        //5.列表迭代器
        ListIterator<String> it2 = list.listIterator();
        while (it2.hasNext()){
            String s = it2.next();
            if ("bbb".equals(s)){
                it2.add("zhangsan");
            }
            System.out.println(s);
        }

        System.out.println(list); // [aaa, bbb, zhangsan, ccc]
    }
五种遍历方式对比

在这里插入图片描述

4.数据结构

  • 数据结构:计算机存储、组织数据的方式
  • 不同的业务场景要选择不同的数据结构。
  • 是指数据之间是以什么方式排列在一起的。
  • 数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。
  • 一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
  1. 每种数据结构长什么样子?
  2. 如何添加数据?
  3. 如何删除数据?
    在这里插入图片描述
1).栈

栈的特点:后进先出,先进后出
在这里插入图片描述
在这里插入图片描述

2).队列

队列的特点:先进先出,后进后出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3)数组

在这里插入图片描述

  • 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
  • 删除效率低:要将原始数据删除,同时后面每个数据前移。
  • 添加效率极低:添加位置后的每个数据后移,再添加元素。

**数组是一种查询快,增删慢的模型。

4)链表

在这里插入图片描述
在这里插入图片描述

  • 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
  • 链表查询慢,无论查询哪个数据都要从头开始找。
  • 链表增删相对快。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
小结

在这里插入图片描述

5)树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

6)二叉查找树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

前序遍历:
在这里插入图片描述

中序遍历:
在这里插入图片描述
后序遍历:
在这里插入图片描述
层序遍历:
在这里插入图片描述
在这里插入图片描述

7)平衡二叉树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

平衡二叉树旋转机制——左旋

就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

请添加图片描述

平衡二叉树旋转机制——右旋

就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
在这里插入图片描述
在这里插入图片描述
请添加图片描述
平衡二叉树和二叉查找树对比结构图
在这里插入图片描述

平衡二叉树需要旋转的四种情况
  1. 左左

    • 左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行右旋即可
      在这里插入图片描述
      在这里插入图片描述

  2. 左右

    • 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
    • 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
      在这里插入图片描述
  3. 右右

    • 右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡

    • 如何旋转: 直接对整体进行左旋即可
      在这里插入图片描述

  4. 右左

    • 右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡

    • 如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8)红黑树

在这里插入图片描述
平衡二叉树:

  • 高度平衡
  • 当左右子树高度差超过1时,通过旋转保持平衡

红黑树:

  • 是一个二叉查找树
  • 但是不是高度平衡的
  • 条件:特有的红黑规则

红黑规则

  1. 每一个结点或是红色的,或是黑色的
  2. 根节点必须是黑色
  3. 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为 Nil ,这些 Nil 视为叶节点,每个叶节点(Nil)是黑色的
  4. 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
  5. 对每一个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
    在这里插入图片描述
    在这里插入图片描述
添加节点的规则

默认颜色:添加节点默认是红色的(效率高

当默认是黑色时:
在这里插入图片描述
当默认是红色时:
在这里插入图片描述
红黑树添加节点后如何保持红黑规则

  • 根节点位置
    • 直接变为黑色
  • 非根节点位置
    • 父节点为黑色
      • 不需要任何操作,默认红色即可
    • 父节点为红色
      • 叔叔节点为红色
        1. 将"父节点"设为黑色,将"叔叔节点"设为黑色
        2. 将"祖父节点"设为红色
        3. 如果"祖父节点"为根节点,则将根节点再次变成黑色
      • 叔叔节点为黑色
        1. 将"父节点"设为黑色
        2. 将"祖父节点"设为红色
        3. 以"祖父节点"为支点进行旋转

在这里插入图片描述
举例:
在这里插入图片描述
跳过添加20、18、23
在这里插入图片描述
在这里插入图片描述
全部添加完成后:
在这里插入图片描述
再向其中添加 15 和 14
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

红黑树增删改查的性能都很好

5.ArrayList集合

在这里插入图片描述

1.ArrayList集合底层原理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.LinkedList集合

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.迭代器底层源码解析

在这里插入图片描述
在这里插入图片描述

6.泛型深入

1)泛型概述

在这里插入图片描述
没有泛型的时候,集合如何存储数据?

public static void main(String[] args) {
        //没有泛型的时候,集合如何存储数据
        /*结论:
            * 如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型
            * 此时可以往集合添加任意的数据类型。
            * 带来一个坏处:我们在获取数据的时候,无法使用它的特有行为。*/
        
        /*此时推出了泛型 ,可以在添加数据的时候就把类型进行统一。
        * 而且我们在获取数据的时候,也省的强转了,非常的方便。*/
        //0.创建集合对象
        ArrayList<Object> list = new ArrayList<>();

        //1.添加数据
        list.add(123);
        list.add("abc");
        list.add(new Student("zhangsan", 123));

        //2.遍历集合获取集合中的每一个元素
        Iterator<Object> it = list.iterator();
        while (it.hasNext()){
            Object obj = it.next();
            //多态的弊端是不能访问子类的特有功能
            System.out.println(obj);
        }
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2)泛型类

在这里插入图片描述
在这里插入图片描述

package Generics;

import java.util.Arrays;

/*
 * 当在编写一个类的时候,如果不确定类型,那么这个类型就可以定义为泛型类。
 *  */
public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size;

    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 static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        System.out.println(list); // [aaa, bbb, ccc, null, null, null, null, null, null, null]

        MyArrayList<Integer> list2 = new MyArrayList<>();
        list2.add(123);
        list2.add(456);
        list2.add(789);
        System.out.println(list2); // [123, 456, 789, null, null, null, null, null, null, null]
        
        Integer i = list2.get(0);
        System.out.println(i); //123
    }

3)泛型方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package Generics;

import java.util.ArrayList;

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 addAll2(ArrayList<E> list, E...e) {
        for (E element : e) {
            list.add(element);
        }
    }
}

package Generics;

import java.util.ArrayList;

public class GenericsDemo3 {
    //定义一个工具类:ListUtil
    //类中定义一个静态方法addAll,用来添加多个集合的元素。
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        ListUtil.addAll(list, "aaa", "bbb", "ccc","ddd" );
        System.out.println(list);//[aaa, bbb, ccc, ddd]

        ArrayList<Integer> list1 = new ArrayList<>();
        ListUtil.addAll2(list1,1,2,3,4,5,6,7,8,9,3,6,4,2,5);
        System.out.println(list1);
    }
}


4)泛型接口

在这里插入图片描述

package Generics;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

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 static void main(String[] args) {
        /*泛型接口的两种使用方式:
            * 1.实现类给出具体的类型
            * 2.实现类延续泛型,创建实现类对象时再确定类型 */

        MyArrayList2 list = new MyArrayList2();
        list.add("abc");

        //list.add(123); // java: 不兼容的类型: int无法转换为java.lang.String

    }

5)泛型的继承和通配符
  • 泛型不具备继承性,但是数据具备继承性
    • 泛型里面写的是什么类型,那么在方法中只能传递什么类型的数据。、

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

package Generics.Test;

public abstract class Animal {
    /*属性:名字,年龄
    行为:吃东西*/

    private String name;
    private int age;


    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 abstract void eat();

    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
}

package Generics.Test;

public abstract class Cat extends Animal{
}

package Generics.Test;

public abstract class Dog extends Animal{
}

package Generics.Test;

public class PersianCat extends Cat {
    @Override
    public void eat() {
        System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");
    }
}

package Generics.Test;

public class LiHuaCat extends Cat {
    @Override
    public void eat() {
        System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");
    }
}

package Generics.Test;

public class HuskyDog extends Dog {
    @Override
    public void eat() {
        System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");
    }
}

package Generics.Test;

public class TeddyDog extends Dog {
    @Override
    public void eat() {
        System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");
    }
}

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> list1 = new ArrayList<>();
        ArrayList<LiHuaCat> list2 = new ArrayList<>();
        ArrayList<TeddyDog> list3 = new ArrayList<>();
        ArrayList<HuskyDog> list4 = new ArrayList<>();

        keepPet(list1);
        keepPet(list2);
        keepPet(list3);
        keepPet(list4);
    }

    //要求3:该方法能养所有的动物,但是不能传递其他类型
    public static void keepPet(ArrayList<? extends Animal> list){}

    //要求2:该方法能养所有品种的狗,但是不能养猫
    /*public static void keepPet(ArrayList<? extends Dog> list){}*/

    //要求1:该方法能养所有品种的猫,但是不能养狗
    /*public static void keepPet(ArrayList<? extends Cat> list){
    }*/

总结

在这里插入图片描述
在这里插入图片描述

7.Set系列集合

  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

在这里插入图片描述

  • 无序:存取顺序不一致
  • 不重复:可以去除重复
  • 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素

Set 集合的实现类

  • HashSet :无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:可排序、不重复、无索引
    Set 接口中的方法上基本上与Collection的API一致
    在这里插入图片描述
    在这里插入图片描述
public static void main(String[] args) {
        /*练习 存储字符串并遍历
         * 利用Set系列的集合,添加字符串,并使用多种方式遍历
         * 0.迭代器
         * 1.增强for
         * 2.Lambda表达式*/

        //0.创建Set集合的对线
        Set<String> s = new HashSet<>();

        //1.添加元素
        /*如果当前元素是第一次添加,那么可以添加成功,返回true
         * 如果当前元素是第二次添加,那么添加失败,返回false*/
        s.add("张三");
        s.add("李四");
        s.add("王五");

        //2.打印集合
        System.out.println(s); // [李四, 张三, 王五]

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

        //增强for遍历
        for (String s2 : s) {
            System.out.println(s2);
        }
        System.out.println("=========================");

        //Lambda 表达式
        /*s.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });*/

        s.forEach(s3 -> System.out.println(s3));
    }
1)HashSet

HashSet 底层原理

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

哈希表组成

  • JDK8之前:数组+链表
  • JDK8开始:数组+链表+红黑树

哈希值:对象的整数表现形式
在这里插入图片描述哈希值

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

在这里插入图片描述

public static void main(String[] args) {
        //0.创建对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("zhangsan", 23);

        //1.如果没有重写hashCode方法,不同对象计算处的哈希值是不同的
        System.out.println(s1.hashCode()); // 990368553
        System.out.println(s2.hashCode()); // 1096979270

        //2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算处的哈希值就是一样的
        System.out.println(s1.hashCode()); // -1461067292
        System.out.println(s2.hashCode()); // -1461067292

        //3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
        System.out.println("abc".hashCode()); // 96354
        System.out.println("acD".hashCode()); // 96354
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        //0.创建学生对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 14);
        Student s3 = new Student("wangwu", 26);
        Student s4 = new Student("zhangsan", 23);

        //1.创建集合用来添加学生
        HashSet<Student> hs = new HashSet<>();

        //2.添加数据
        System.out.println(hs.add(s1)); //true
        System.out.println(hs.add(s2)); //true
        System.out.println(hs.add(s3)); //true
        System.out.println(hs.add(s4)); //false

        System.out.println(hs);
    }
package Set;

import java.util.Objects;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(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 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);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


2)LinkedHashSet

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        //0.创建学生对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 14);
        Student s3 = new Student("wangwu", 26);
        Student s4 = new Student("zhangsan", 23);

        //1.创建集合用来添加学生
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();

        //2.添加数据
        System.out.println(lhs.add(s1)); //true
        System.out.println(lhs.add(s2)); //true
        System.out.println(lhs.add(s3)); //true
        System.out.println(lhs.add(s4)); //false

        System.out.println(lhs); //[Student{name='zhangsan', age=23}, Student{name='lisi', age=14}, Student{name='wangwu', age=26}]
    }

在这里插入图片描述

3)TreeSet

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        /*需求:
         * 存储整数并进行排序 */
        //0.创建TreeSet集合对象
        TreeSet<Integer> ts = new TreeSet<>();

        //1.添加数据
        ts.add(4);
        ts.add(5);
        ts.add(2);
        ts.add(1);
        ts.add(3);

        //2.打印集合
        System.out.println(ts); // [1, 2, 3, 4, 5]

        //3.遍历
        //迭代器
        Iterator<Integer> it = ts.iterator();
        while (it.hasNext()) {
            Integer num = it.next();
            System.out.println(num);
        }

        System.out.println("=================");

        //加强for
        for (Integer t : ts) {
            System.out.println(t);
        }
        System.out.println("======================");

        //Lambda表达式
        ts.forEach(num -> System.out.println(num));

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        /*需求:
        * 创建TreeSet集合,并添加3个学生对象
        * 学生对象属性:
            * 姓名、年龄
            * 要求按照学生的年龄进行排序
            * 同年龄按照姓名字母排列(暂不考虑中文)
            * 同姓名,同年龄认为是同一个人
            *
         * 方式一:
            * 默认的排序规则/自然排序
            * Student实现Comparable接口,重写里面的抽象方法,再指定比较规则
            *
         * 方式二:
            * 比较器排序
            * 创建TreeSet对象的时候,传递比较器Comparator指定规则*/

        //0.创建学生对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 24);
        Student s3 = new Student("wangwu", 25);

        //1.创建集合对象
        TreeSet<Student> ts = new TreeSet<>();

        //2.添加数据
        ts.add(s2);
        ts.add(s1);
        ts.add(s3);

        //3.打印数据
        System.out.println(ts);
    }
package Set;

import java.util.Objects;

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;
    }

    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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        int res = this.getAge() - o.getAge();
        return res;
    }
}


在这里插入图片描述

 public static void main(String[] args) {
        /*
         * 需求:请自行选择比较器排序和自然排序两种方式:
         * 要求:存入四个字符串,c , ab , df , qwer
         * 按照长度排序,如果一样长则按照首字母排序*/

        //0.创建集合
        /*o1:表示当前要添加的元素
         * o2:表示已经在红黑树存在的元素
         * 返回值:
         * 负数:认为要添加的元素是小的,存左边
         * 正数:认为要添加的元素是大的,存右边
         * 0:认为要添加的元素已经存在,舍弃*/
        /*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;
            }
        });*/

        TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
            //按照长度排序
            int i = o1.length() - o2.length();
            //如果一样长则按照首字母排序
            i = i == 0 ? o1.compareTo(o2) : i;
            return i;
        });
        //添加数据
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");

        //打印
        System.out.println(ts); // [c, ab, df, qwer]
    }

在这里插入图片描述

package Set;

public class Student2 implements Comparable<Student2> {
    /*属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)*/
    private String name;
    private int age;
    private int Chinese;
    private int Math;
    private int English;

    public Student2() {
    }

    public Student2(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;
    }

    /**
     * 获取
     *
     * @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 "Student2{name = " + name + ", age = " + age + ", Chinese = " + Chinese + ", Math = " + Math + ", English = " + English + "}";
    }

    /*按照总分从高到低输出到控制台
     * 如果总分一样,按照语文成绩排
     * 如果语文一样,按照数学成绩排
     * 如果数学成绩一样,按照英语成绩排
     * 如果英语成绩一样,按照年龄排
     * 如果年龄一样,按照姓名的字母顺序排
     * 如果都一样,认为是同一个学生,不存*/
    @Override
    public int compareTo(Student2 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;
    }
}

public static void main(String[] args) {
        /*需求:创建5个学生对象
         * 属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)
         * 按照总分从高到低输出到控制台
         * 如果总分一样,按照语文成绩排
         * 如果语文一样,按照数学成绩排
         * 如果数学成绩一样,按照英语成绩排
         * 如果英语成绩一样,按照年龄排
         * 如果年龄一样,按照姓名的字母顺序排
         * 如果都一样,认为是同一个学生,不存。*/

        //0.创建5个学生对象
        Student2 s1 = new Student2("zhangsan", 23, 90, 99, 50);
        Student2 s2 = new Student2("lisi", 24, 90, 98, 50);
        Student2 s3 = new Student2("wangwu", 25, 95, 100, 30);
        Student2 s4 = new Student2("zhaoliu", 26, 60, 99, 70);
        Student2 s5 = new Student2("qianqi", 26, 70, 80, 70);

        //1.创建集合
        TreeSet<Student2> ts = new TreeSet<>();

        //2.添加数据
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);

        //3.打印
        //System.out.println(ts);
        Iterator<Student2> it = ts.iterator();
        while (it.hasNext()) {
            Student2 info = it.next();
            int sum = info.getChinese() + info.getMath() + info.getEnglish();
            System.out.println(info + " 总分:" + sum);
        }
        /*Student2{name = qianqi, age = 26, Chinese = 70, Math = 80, English = 70} 总分:220
          Student2{name = wangwu, age = 25, Chinese = 95, Math = 100, English = 30} 总分:225
          Student2{name = zhaoliu, age = 26, Chinese = 60, Math = 99, English = 70} 总分:229
          Student2{name = lisi, age = 24, Chinese = 90, Math = 98, English = 50} 总分:238
          Student2{name = zhangsan, age = 23, Chinese = 90, Math = 99, English = 50} 总分:239*/
    }

在这里插入图片描述

8.单列集合使用场景

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/397816.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式学习-qt-Day1

嵌入式学习-qt-Day1 一、思维导图 二、作业 1.自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {//字体设置QFont font1;//创建字体对象1font1.setWeight(QFont::Bold);//字体…

普法:正当防卫,保护自己

今天该换一换口味了&#xff0c;所以本“人民体验官”推广人民日报官方微博《警察小哥科普第二十条指什么》。 图&#xff1a;来源“人民体验官”推广平台 电影《第二十条》片名&#xff0c;取自刑法第二十条规定。这一法条具体写了什么&#xff1f;对我们的生活有何影响&…

《白话C++》第10章 STL和boost,Page105 enable_shared_from_this

说到“循环引用”&#xff0c;其中“自己对自己”的引用是最直接的循环引用&#xff0c;如图10-12所示。 而说到“自己”&#xff0c;在C语言中应该首先想到的类的“this”指针。不过&#xff0c;this指针是裸指针&#xff0c;如果我们在类中&#xff0c;需要传递当前对象本身&…

【嵌入式-Keil】keil代码提示快捷键

CTRL空格 如果没有提示&#xff0c;可能跟输入法的快捷键冲突&#xff0c; 右键->设置->按键->勾掉第一个就行了 再按CTRL空格就有提示了 参考&#xff1a;串口发送&串口发送接收

Vue | (三)使用Vue脚手架(中)| 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;Todo-list 案例&#x1f407;组件化编码流程&#xff08;通用&#xff09;&#x1f407;实现静态组件&#x1f407;展示动态数据&#x1f407;交互⭐️添加一个todo⭐️todo勾选实现⭐️删除功能实现⭐️底部统计功能实现⭐️底部全选功能实现⭐️底部一…

【黑马程序员】C++文件操作

20240220 文章目录 文件操作背景文件分类操作文件的三大类 文本文件写文件写文件步骤文件打开方式代码示例 读文件读文件步骤代码示例 写二进制文件写二进制文件步骤代码示例 读二进制文件代码示例 文件操作 背景 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行…

TypeScript(三):TypeScript面向对象

TypeScript面向对象 类的定义 与JS不同的是&#xff0c;成员属性需要在前面进行提前声明 class Person{//需要在前面对成员变量进行声明name: string//声明的时候&#xff0c;可以对值进行初始化&#xff0c;初始化可以带有类型注解&#xff0c;也可以省略age 18//construc…

基于YOLOv7算法和Widerperson数据集的高精度实时行人检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法和Widerperson数据集的高精度实时行人检测系统可用于日常生活中检测与定位行人目标&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检…

3个密码学相关的问题

一、离散对数问题&#xff08;Discrete Logarithm Problem, DLP&#xff09; 问题描述&#xff1a;给定 有限阿贝尓群 G中的2个元素a和b&#xff0c;找出最小的正整数x满足&#xff1a;b a ^^ x &#xff08;或者证明这样的x不存在&#xff09;。 二、阶数问题&#xff08;O…

云服务器ECS价格表出炉——阿里云

2024年阿里云服务器租用价格表更新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年、ECS u1实例2核4G、5M固定带宽、80G ESSD Entry盘优惠价格199元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元、2核4G4M带宽轻量服务器一年165元12个月、2核4G服…

[element] el-upload实现 “读取本地表格内容并上传“

需求: 通过表格一键导入数据 表格模板: 导入按钮: <el-uploadref"upload"class"filter-item"style"margin-left: 10px"action"/"accept".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.sp…

Open3D三维重建

原始点云&#xff1a; alpha_shape算法 import open3d as o3dpcd o3d.io.read_point_cloud("airplane_0001.pcd") mesh o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha0.1) o3d.visualization.draw_geometries([mesh], mesh_show_b…

相机图像质量研究(39)常见问题总结:编解码对成像的影响--运动模糊

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

我把ChatGPT部署到我的手机上

正常的大模型部署都是在服务器上的 但是最近我看到一个手机上可以运行的大模型 分享给大家 MiniCPM MiniCPM是基于 MLC-LLM 开发&#xff0c;将 MiniCPM 和 MiniCPM-V 在 Android 手机端上运行。 使用起来很简单&#xff0c;下载好安装包后 按照教程安装好 下载2个模型 一个是M…

C++拷贝构造函数与赋值运算符重载

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、拷贝构造函数 1.概念 在现实生活中&#xff0c;可能存在一个与你一样的自己&#xff0c;我们称其为双胞胎。 那在创…

虹科方案丨低负载ECU老化检测解决方案:CANCAN FD总线“一拖n”

来源&#xff1a;虹科汽车智能互联 虹科方案丨低负载ECU老化检测解决方案&#xff1a;CANCAN FD总线“一拖n” 原文链接&#xff1a;https://mp.weixin.qq.com/s/4tmhyE5hxeLFCiaeoRhlSg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #汽车总线 #ECU #CAN卡 导读 …

配置Python环境及job运行的虚拟环境

1、配置Jenkins的Python环境&#xff1a;Manage Jnekins-Global Tool Configuration-Python 2、安装pyenv插件 此插件会给每个job都创建一个虚拟Python环境 安装后&#xff0c;在job config-build中选择 virtualenv builder build job的时候会自动在/opt/jenkins(node主机的…

详解平面点云面积计算

部分代码展示&#xff1a; &#xff08;1&#xff09;利用格网法计算面积&#xff1a; //&#xff08;2&#xff09;测试使用格网法计算平面点云面积 void main() {char *inputpath "D:\\testdata\\data.txt";vector<pcl::PointXYZ> points ReadPointXYZIn…

vue的十大面试题详情

1 v-show与v-if区别 v-if与v-show可以根据条件的结果,来决定是否显示指定内容&#xff1a; v-if: 条件不满足时, 元素不会存在. v-show: 条件不满足时, 元素不会显示(但仍然存在). <div id"app"><button click"show !show">点我</but…

【动态规划专栏】专题二:路径问题--------6.地下城游戏

本专栏内容为&#xff1a;算法学习专栏&#xff0c;分为优选算法专栏&#xff0c;贪心算法专栏&#xff0c;动态规划专栏以及递归&#xff0c;搜索与回溯算法专栏四部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握算法。 &#x1f493;博主csdn个人主页&#xff1a;小…