1. 集合与泛型

1. 学习内容

  1. 集合框架的体系

  2. List集合以及相关类

  3. 泛型详解

  4. Set集合以及相关类

  5. Map集合以及相关类

  6. 集合的遍历和迭代器

  7. 比较器的使用

  8. 集合工具类

2. 学习目标

  1. 集合框架的体系-->理解

  2. List集合以及相关类-> 掌握

    1. ArrayList-->掌握

    2. LinkedList-->掌握

    3. Vector-->掌握

  3. 泛型详解

    1. 集合中使用泛型-->掌握

    2. 自定义泛型-->掌握

  4. Set集合以及相关类

    1. HashSet-->熟悉

    2. LinkedHasSet-->熟悉

    3. TreeSet-->熟悉

  5. Map集合以及相关类

    1. HashMap-->掌握

    2. LinkedHashMap-->熟悉

    3. HashTable-->熟悉

    4. TreeMap-->熟悉

    5. HashMap源码分析

  6. 集合的遍历和迭代器-->掌握

  7. 比较器的使用-->熟悉

  8. 集合工具类-->熟悉

3. 课堂笔记

1. 集合

1. 集合的介绍

在编程中会经常使用数据用于存储,以及交互,如果我们存储时需要存储多个数据则能够使用的较少(数组),然而数组他的缺点很多,在使用时非常麻烦 所以Java又提供了集合的概念,集合与数组相同都是用于存储多个数据(元素),但是不同点在于集合属于引用数据类型,集合使用时提供的方法更多,使用起来更加简单

数组的缺点:增删慢,一旦初始化长度则无法改变(Arrays的方法可以改),只能存储同一种类型,空间一旦确定就是在内存开辟所有空间占用较多,数组操作不方便 数组的优点:查询速度快(通过小标索引直接获取元素),是一种简单的线性序列,数组存储非常简单 集合的出现解决了很多数组存在的问题,例如占用空间多,长度不能更改,增删慢,查询快,还提供了非常多操作数据的方法使用起来更加方便 并且集合有很多种,根据不同需求使用不同的集合也能够解决很大的问题 集合分为两大类

  1. 存储单数据-->Collection集合

  2. 存储双数据-->Map集合

2. 集合的体系结构

体系结构类似于族谱,会从最顶部(祖宗)向下延伸(子孙),结构体系就是继承(实现)关系,存在父子关系就形成体系结构,体系结构只需要看具体的实现类 体系结构中一般祖宗提供的仅仅只是血统(程序中的方法),子孙类只需要继承(实现)祖宗的方法重写即可

1. Collection集合体系

下图为Collection集合体系,其中包含List集合以及Set集合,以及其子孙类

 

转存失败

重新上

2. Map集合体系

下图为Map集合体系结构,其中包含直接子类

2. Collection接口(重点)`

Collection接口概述

Collection接口是集合祖先类(超类),其中定义了最初的通用方法,并且子孙类都会实现,Collection接口使用的较少,一般都是直接使用其子孙

1. Collection接口
1. Collection常用方法
  1. boolean add(E e);:向集合中添加新的元素

  2. boolean addAll(Collection<? extends E> c);:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中

    1. c:Collection以及子孙类都可以,集合参数

  3. boolean remove(Object o);:从集合中移除指定元素

  4. boolean removeAll(Collection<?> c);:从集合中移除c集合的所有相同元素

  5. void clear();:清空集合(将所有元素删除)

  6. boolean contains(Object o);:判断集合中是否包含指定元素

  7. boolean containsAll(Collection<?> c);:判断集合中是否包含指定集合的元素

  8. boolean equals(Object o);:判断集合是否相同

  9. boolean isEmpty();:判断集合是否为空(不是null)

  10. Iterator<E> iterator();:返回集合可迭代对象

  11. Object[] toArray();:将集合转为数组

  12. int size();:返回集合长度(元素数量)

  13. default Stream<E> stream():返回集合的Stream流

2. List接口(重点)
1. List接口概述

List接口是一个有序的并且可重复,以及值可为null的集合,也可以称之为序列 有序:存储顺序与取出顺序一致,并且可以通过下标索引直接获取元素 可重复:存储的元素允许出现重复的,并且支持存储null数据 List接口是Collection接口的直接子接口,其中添加了一些新的方法,以及原本Collection接口的方法同样也拥有

2. List接口常用方法
  1. void add(int index, E element);:向集合中指定位置插入元素

  2. boolean addAll(int index, Collection<? extends E> c);:向集合中指定位置插入c集合的所有元素

  3. E get(int index);:获取集合中指定位置的元素

  4. int indexOf(Object o);:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1

  5. int lastIndexOf(Object o);:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1

  6. E remove(int index);:通过下标索引删除集合中的元素

  7. E set(int index, E element);:修改指定下标索引的元素

  8. default void sort(Comparator<? super E> c):通过比较器给集合排序

  9. List<E> subList(int fromIndex, int toIndex);:通过指定起始位置以及结束位置裁剪集合

由于List是接口,无法创建对象,所以无法直接使用,只能通过其子孙类使用

2. List接口实现类之ArrayList类(重点)
1. ArrayList类概述

ArrayList是List接口的直接实现子类,其中完美的重写了所有List接口的方法 ArrayList底层是使用动态数组实现(通过Arrays工具类实现的动态数组),动态数组是指数组长度可以动态扩容 ArrayList有数组除了不可变长度之外的所有优缺点 ArrayList是通过Object存储数组数据

2. ArrayList构造方法
// 通过无参构造方法创建ArrayList对象
public ArrayList() {
    // 初始化ArrayList数组对象
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 通过带参构造方法指定初始化容量创建ArrayList对象
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
    }
}
// 通过带参构造方法指定集合创建ArrayList对象
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
3. ArrayList常用方法
  1. boolean add(E e);:向集合中添加新的元素

  2. void add(int index, E element);:向集合中指定位置插入元素

  3. boolean addAll(Collection<? extends E> c);:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中

    1. c:Collection以及子孙类都可以,集合参数

  4. boolean addAll(int index, Collection<? extends E> c);:向集合中指定位置插入c集 合的所有元素

  5. E get(int index);:获取集合中指定位置的元素

  6. boolean contains(Object o);:判断集合中是否包含指定元素

  7. boolean containsAll(Collection<?> c);:判断集合中是否包含指定集合的元素

  8. int indexOf(Object o);:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1

  9. int lastIndexOf(Object o);:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1

  10. boolean remove(Object o);:从集合中移除指定元素

  11. E remove(int index);:通过下标索引删除集合中的元素

  12. boolean removeAll(Collection<?> c);:从集合中移除c集合的所有相同元素

  13. E set(int index, E element);:修改指定下标索引的元素

  14. default void sort(Comparator<? super E> c):通过比较器给集合排序

  15. List<E> subList(int fromIndex, int toIndex);:通过指定起始位置以及结束位置裁剪集合

  16. boolean equals(Object o);:判断集合是否相同

  17. Object[] toArray();:将集合转为数组

  18. int size();:返回集合长度(元素数量)

  19. void clear();:清空集合(将所有元素删除)

  20. boolean isEmpty();:判断集合是否为空(不是null)

  21. Iterator<E> iterator();:返回集合可迭代对象

  22. default Stream<E> stream():返回集合的Stream流

4. ArrayList代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建ArrayList对象
        ArrayList arrayList = new ArrayList();
        // 1. `boolean add(E e);`:向集合中添加新的元素
        System.out.println("========================add========================");
        arrayList.add("梅超风");
        arrayList.add(1234);
        arrayList.add("天山童姥");
        arrayList.add("肾虚公子");
        arrayList.add("吴签");
        arrayList.add(12.34);
        arrayList.add(true);
        System.out.println(arrayList);
        // 2. `void add(int index, E element);`:向集合中指定位置插入元素
        arrayList.add(0, "基尼太美");
        System.out.println(arrayList);
        // 3. `boolean addAll(Collection<? extends E> c);`:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中
        // 1. c:Collection以及子孙类都可以,集合参数
        System.out.println("========================addAll========================");
        arrayList.addAll(arrayList);
        System.out.println(arrayList);
        // 4. `boolean addAll(int index, Collection<? extends E> c);`:向集合中指定位置插入c集合的所有元素
        System.out.println("========================addAll========================");
        arrayList.addAll(1, arrayList);
        System.out.println(arrayList);
        // 5. `E get(int index);`:获取集合中指定位置的元素
        // 如果下标索引超出元素数量则抛下标索引越界异常
        System.out.println("========================get========================");
        Object value = arrayList.get(0);
        System.out.println(value);
        // 6. `boolean contains(Object o);`:判断集合中是否包含指定元素
        System.out.println("========================contains========================");
        boolean isContains = arrayList.contains("基尼太美");
        System.out.println(isContains);
        // 7. `boolean containsAll(Collection<?> c);`:判断集合中是否包含指定集合的元素
        System.out.println("========================containsAll========================");
        boolean containsAll = arrayList.containsAll(arrayList);
        System.out.println(containsAll);
        // 8. `int indexOf(Object o);`:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("========================indexOf========================");
        int indexOf = arrayList.indexOf("基尼太美");
        System.out.println(indexOf);
        indexOf = arrayList.indexOf("基尼太美哦哦哦哦哦");
        System.out.println(indexOf);
        // 9. `int lastIndexOf(Object o);`:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("========================lastIndexOf========================");
        int lastIndexOf = arrayList.lastIndexOf("基尼太美");
        System.out.println(lastIndexOf);
        lastIndexOf = arrayList.lastIndexOf("基尼太美哦哦哦哦哦");
        System.out.println(lastIndexOf);
        // 10. `boolean remove(Object o);`:从集合中移除指定元素
        System.out.println("========================remove========================");
        boolean isRemove = arrayList.remove("基尼太美");
        System.out.println(isRemove);
        isRemove = arrayList.remove("基尼太美123");
        System.out.println(isRemove);
        System.out.println(arrayList);
        // 11. `E remove(int index);`:通过下标索引删除集合中的元素
        System.out.println("========================remove========================");
        Object remove = arrayList.remove(2);
        System.out.println(remove);
        System.out.println(arrayList);
        // 12. `boolean removeAll(Collection<?> c);`:从集合中移除c集合的所有相同元素
        System.out.println("========================removeAll========================");
        boolean removeAll = arrayList.removeAll(arrayList);
        System.out.println(removeAll);
        System.out.println(arrayList);
        arrayList.add("梅超风");
        arrayList.add(1234);
        arrayList.add("天山童姥");
        arrayList.add("肾虚公子");
        arrayList.add("吴签");
        arrayList.add(12.34);
        arrayList.add(true);
        // 13. `E set(int index, E element);`:修改指定下标索引的元素
        System.out.println("========================set========================");
        Object set = arrayList.set(1, 5678);
        System.out.println(set);
        System.out.println(arrayList);
        // 14. `default void sort(Comparator<? super E> c)`:通过比较器给集合排序
        System.out.println("========================sort========================");
        // 15. `List<E> subList(int fromIndex, int toIndex);`:通过指定起始位置以及结束位置裁剪集合
        System.out.println("========================subList========================");
        List list = arrayList.subList(3, 4);
        System.out.println(list);
        // 16. `boolean equals(Object o);`:判断集合是否相同
        System.out.println("========================equals========================");
        boolean equals = arrayList.equals(list);
        System.out.println(equals);
        equals = arrayList.equals(arrayList);
        System.out.println(equals);
        // 17. `Object[] toArray();`:将集合转为数组
        System.out.println("========================toArray========================");
        Object[] objects = arrayList.toArray();
        System.out.println(Arrays.toString(objects));
        // 18. `int size();`:返回集合长度(元素数量)
        System.out.println("========================size========================");
        int size = arrayList.size();
        System.out.println(size);
        // 19. `void clear();`:清空集合(将所有元素删除)
        System.out.println("========================clear========================");
        arrayList.clear();
        System.out.println(arrayList);
        // 20. `boolean isEmpty();`:判断集合是否为空(不是null)
        System.out.println("========================isEmpty========================");
        boolean empty = arrayList.isEmpty();
        System.out.println(empty);
        arrayList.add("基尼太美");
        System.out.println(arrayList);
        empty = arrayList.isEmpty();
        System.out.println(empty);
    }
}
3. List接口实现类之LinkedList类(熟悉)
1. LinkedList概述

LinkedList与ArrayList相同是List接口的直接实现子类,但是区别在于底层实现,ArrayList使用的是动态数组实现,LinkedList底层是使用双链表结构实现 双链表结构的优缺点,链表不同于数组,存储数据时不需要连续的空间,并且不需要初始化容量,在删除以及新增是速度飞快,但是查询的速度慢(原因是他没有下标索引) LinkedList与ArrayList正好是相反的作用

1. 链表是什么,分为几种

链表概述,链表是非连续空间,数据的存储关联是由对象指向下一个存储空间的内存地址来查找,他的长度是可以无限增涨并且不会出现浪费空间的情况 一般链表最低需要两个元素,两个元素代表一个存储单元,存储单元中分为元素以及next(指针,指向下一个元素) 链表分为几种:1. 单链表结构,2. 双链表结构,3. 循环单链表结构,4. 循环双链表结构

  1. 单链表结构存储方式

    1. 单链表存储方式,是有一个存储单元组成,一个存储单元中存在两个数据,数据1:存储元素,数据2:存储指向下一个单元的内存地址

    2. 存储单元一般被称之为node节点,存储元素的小单元为称之为data,存储下一个节点的数据的一般呗称之为next(指针)

    3. 第一个Node节点对象为首节点,最后一个Node节点对象为尾结点

  2. 双链表结构存储方式

    1. 双链表结构是单链表的升级版本,单链表只会指向后一个Node节点对象,双链表则前后会指向,丛任意一个位置都可向前或向后查询元素,但是首节点不能向前尾结点不能向后

    2. 双链表结构:分为三个部分;1. prev:指向前一个节点对象,2. data:存储的元素数据,3. next:指向下一个节点对象

    3. 双链表第一个Node节点为首节点,最后一个Node节点为尾结点,首节点prev指向null,尾结点next也指向null

  3. 环形单链表存储方式

    1. 环形单链表与单链表相同,唯一的却别是尾结点重新指向首节点,则可以无限循环查询

    2. 环形单链表与单链表存储单元相同,分为1. data:存储元素数据,2. next:存储下一个节点地址

  4. 环形双链表存储方式

    1. 环形双链表与双链表结构相同,唯一的却别在于首节点的prev不在指向null,而是指向尾结点,相同尾结点的next不在指向null,而是指向首节点

    2. 环形双链表存储单元分为3个,1. prev:指向前一个节点,2. data:存储元素数据,3. next:指向下一个节点

    3. 环形双链表结构首节点的prev指向尾结点,尾结点的next指向首节点,形成环状

LinkedList就是以双链表为主实现的集合,存储数据时就是通过节点对象为单元存储,存储对象被命名为Node节点,Node节点对象中有三个属性,第一个属性是prev是Node类型用于存储上一个节点对象,第二个属性是item是用于存储数据,第三个属性是next是Node类型,用于存储下一个节点对象 LinkedList的Node节点实现-->LinkedList的底层数据存储格式

// Node节点类
private static class Node<E> {
    // item就是data用于存储数据
    E item;
    // next就是指向下一个节点对象地址
    Node<E> next;
    // prev就是指向上一个节点对象地址
    Node<E> prev;
​
    // Node节点对象构造方法
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}
2. LinkedList构造方法
// 空参构造方法用于创建LinkedList对象
public LinkedList() {
}
// 将指定集合元素添加到LinkedList对象中并创建LinkedList对象
public LinkedList(Collection<? extends E> c) {
    // 当前空参构造方法
    this();
    // 调用自身方法addAll添加所有数据
    addAll(c);
}
3. LinkedList常用方法
  1. boolean add(E e);:向集合中添加新的元素

  2. void add(int index, E element);:向集合中指定位置插入元素

  3. boolean addAll(Collection<? extends E> c);:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中

    1. c:Collection以及子孙类都可以,集合参数

  4. boolean addAll(int index, Collection<? extends E> c);:向集合中指定位置插入c集合的所有元素

  5. E get(int index);:获取集合中指定位置的元素

  6. boolean contains(Object o);:判断集合中是否包含指定元素

  7. boolean containsAll(Collection<?> c);:判断集合中是否包含指定集合的元素

  8. int indexOf(Object o);:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1

  9. int lastIndexOf(Object o);:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1

  10. boolean remove(Object o);:从集合中移除指定元素

  11. E remove(int index);:通过下标索引删除集合中的元素

  12. boolean removeAll(Collection<?> c);:从集合中移除c集合的所有相同元素

  13. E set(int index, E element);:修改指定下标索引的元素

  14. default void sort(Comparator<? super E> c):通过比较器给集合排序

  15. List<E> subList(int fromIndex, int toIndex);:通过指定起始位置以及结束位置裁剪集合

  16. boolean equals(Object o);:判断集合是否相同

  17. Object[] toArray();:将集合转为数组

  18. int size();:返回集合长度(元素数量)

  19. void clear();:清空集合(将所有元素删除)

  20. boolean isEmpty();:判断集合是否为空(不是null)

  21. Iterator<E> iterator();:返回集合可迭代对象

  22. default Stream<E> stream():返回集合的Stream流

  23. public void addFirst(E e):在首部插入元素

  24. public void addLast(E e):在尾部添加元素

  25. public E getFirst():获取第一个节点元素

  26. public E getLast():获取最后一个节点元素

  27. public E removeFirst():移除第一个节点元素

  28. public E removeLast():移除最后一个节点元素

  29. public boolean offerFirst(E e):将指定元素插入到列表开头

  30. public boolean offerLast(E e):将指定元素插入到列表结尾

  31. public E peekFirst():获取首节点元素,但是不删除

  32. public E peekLast():获取尾结点元素,但是不删除

  33. public E pollFirst():获取首节点元素,并删除

  34. public E pollLast():获取尾结点元素,并删除

4. LinkedList代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建LinkedList对象
        LinkedList linkedList = new LinkedList();
        // 1. `boolean add(E e);`:向集合中添加新的元素
        System.out.println("=============================add=============================");
        linkedList.add("彭于晏");
        linkedList.add("梅超风");
        linkedList.add("基尼太美");
        linkedList.add("灭绝师太");
        linkedList.add("裘千仞");
        linkedList.add("裘千尺");
        linkedList.add(1.23);
        System.out.println(linkedList);
        // 2. `void add(int index, E element);`:向集合中指定位置插入元素
        System.out.println("=============================add=============================");
        linkedList.add(1, "李莫愁");
        System.out.println(linkedList);
        // 3. `boolean addAll(Collection<? extends E> c);`:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中
        System.out.println("=============================add=============================");
        // 4. `boolean addAll(int index, Collection<? extends E> c);`:向集合中指定位置插入c集合的所有元素
        System.out.println("=============================add=============================");
        // 5. `E get(int index);`:获取集合中指定位置的元素
        System.out.println("=============================get=============================");
        Object value = linkedList.get(0);
        System.out.println(value);
        // 6. `boolean contains(Object o);`:判断集合中是否包含指定元素
        System.out.println("=============================contains=============================");
        boolean isContains = linkedList.contains("彭于晏");
        System.out.println(isContains);
        // 7. `boolean containsAll(Collection<?> c);`:判断集合中是否包含指定集合的元素
        System.out.println("=============================add=============================");
        // 8. `int indexOf(Object o);`:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("=============================add=============================");
        // 9. `int lastIndexOf(Object o);`:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("=============================add=============================");
        // 10. `boolean remove(Object o);`:从集合中移除指定元素
        System.out.println("=============================remove=============================");
        Object remove = linkedList.remove(1.23);
        System.out.println(remove);
        System.out.println(linkedList);
        // 11. `E remove(int index);`:通过下标索引删除集合中的元素
        System.out.println("=============================remove=============================");
        Object remove1 = linkedList.remove(2);
        System.out.println(remove1);
        System.out.println(linkedList);
        // 12. `boolean removeAll(Collection<?> c);`:从集合中移除c集合的所有相同元素
        System.out.println("=============================add=============================");
        // 13. `E set(int index, E element);`:修改指定下标索引的元素
        System.out.println("=============================set=============================");
        Object set = linkedList.set(3, "胖头陀");
        System.out.println(set);
        System.out.println(linkedList);
        // 14. `default void sort(Comparator<? super E> c)`:通过比较器给集合排序
        System.out.println("=============================add=============================");
        // 15. `List<E> subList(int fromIndex, int toIndex);`:通过指定起始位置以及结束位置裁剪集合
        System.out.println("=============================add=============================");
        // 16. `boolean equals(Object o);`:判断集合是否相同
        System.out.println("=============================add=============================");
        // 17. `Object[] toArray();`:将集合转为数组
        System.out.println("=============================add=============================");
        // 18. `int size();`:返回集合长度(元素数量)
        System.out.println("=============================size=============================");
        System.out.println(linkedList.size());
        // 19. `void clear();`:清空集合(将所有元素删除)
        System.out.println("=============================add=============================");
        // 20. `boolean isEmpty();`:判断集合是否为空(不是null)
        System.out.println("=============================isEmpty=============================");
        System.out.println(linkedList.isEmpty());
        // 21. `Iterator<E> iterator();`:返回集合可迭代对象
        System.out.println("=============================add=============================");
        // 22. `default Stream<E> stream()`:返回集合的Stream流
        System.out.println("=============================add=============================");
        // 23. `public void addFirst(E e)`:在首部插入元素
        System.out.println("=============================addFirst=============================");
        linkedList.addFirst("向头部插入数据");
        // 24. `public void addLast(E e)`:在尾部添加元素
        System.out.println("=============================addLast=============================");
        linkedList.addLast("向尾部添加数据");
        System.out.println(linkedList);
        // 25. `public E getFirst()`:获取第一个节点元素
        System.out.println("=============================getFirst=============================");
        Object first = linkedList.getFirst();
        System.out.println(first);
        // 26. `public E getLast()`:获取最后一个节点元素
        System.out.println("=============================getLast=============================");
        Object last = linkedList.getLast();
        System.out.println(last);
        // 27. `public E removeFirst()`:移除第一个节点元素
        System.out.println("=============================removeFirst=============================");
        Object removeFirst = linkedList.removeFirst();
        System.out.println(removeFirst);
        System.out.println(linkedList);
        // 28. `public E removeLast()`:移除最后一个节点元素
        System.out.println("=============================removeLast=============================");
        Object removeLast = linkedList.removeLast();
        System.out.println(removeLast);
        System.out.println(linkedList);
        // 29. `public boolean offerFirst(E e)`:将指定元素插入到列表开头
        System.out.println("=============================offerFirst=============================");
        boolean offerFirst = linkedList.offerFirst("offerFirst");
        System.out.println(offerFirst);
        System.out.println(linkedList);
        // 30. `public boolean offerLast(E e)`:将指定元素插入到列表结尾
        System.out.println("=============================offerLast=============================");
        boolean offerLast = linkedList.offerLast("offerLast");
        System.out.println(offerLast);
        System.out.println(linkedList);
        // 31. `public E peekFirst()`:获取首节点元素,但是不删除
        System.out.println("=============================peekFirst=============================");
        Object peekFirst = linkedList.peekFirst();
        System.out.println(peekFirst);
        System.out.println(linkedList);
        // 32. `public E peekLast()`:获取尾结点元素,但是不删除
        System.out.println("=============================peekLast=============================");
        Object peekLast = linkedList.peekLast();
        System.out.println(peekLast);
        System.out.println(linkedList);
        // 33. `public E pollFirst()`:获取首节点元素,并删除
        System.out.println("=============================pollFirst=============================");
        Object pollFirst = linkedList.pollFirst();
        System.out.println(pollFirst);
        System.out.println(linkedList);
        // 34. `public E pollLast()`:获取尾结点元素,并删除
        System.out.println("=============================pollLast=============================");
        Object pollLast = linkedList.pollLast();
        System.out.println(pollLast);
        System.out.println(linkedList);
    }
}
5. LinkedList存储方式源码分析

LinkedList的数据存储都是使用的Node节点对象,并且默认存储时指向第一个和最后一个Node节点对象,用于便捷操作

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
    // 集合元素长度
    transient int size = 0;
​
    // 指向第一个节点的指针。不变量:(first == null && last == null) || (first.prev == null && first.item != null)
    transient Node<E> first;
​
    // 指向最后一个节点的指针。不变量:(first == null && last == null) || (last.next == null && last.item != null)
    transient Node<E> last;
    
    // Node内部类就是LinkedList的存储格式
    // Node节点类
    private static class Node<E> {
        // item就是data用于存储数据
        E item;
        // next就是指向下一个节点对象地址
        Node<E> next;
        // prev就是指向上一个节点对象地址
        Node<E> prev;
​
        // Node节点对象构造方法
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
}
4. List接口实现类之Vector类(熟悉)
1. Vector概述

Vector与ArrayList是相同的,尤其是用法基本完全一致,唯一的区别在于ArrayList是线程不安全的,而Vector是线程安全 线程安全代表在多线程情况下能够保证数据的安全性,不会因为多线程操作而导致数据的确定性(数据结果与最终想要的结果不一致) 线程安全与线程不安全的体现在于这两个类中的方法修饰,线程安全会多一个关键字synchronized线程同步关键字,线程不安全的则没有此关键字修饰 以上就是Vector与ArrayList的区别,其他的方法基本上完全一致 线程安全会造成程序的运行效率降低,线程不安全则不会影响效率问题

2. Vector构造方法
// 使用空参构造方法创建对象
public Vector() {
    // 默认初始化容量为10(10个元素)
    this(10);
}
// 使用带参构造方法指定初始容量大小,创建对象
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}
// 使用带参构造方法创建对象,并将其他集合的数据添加至创建的对象内
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
3. Vector常用方法
  1. boolean add(E e);:向集合中添加新的元素

  2. void add(int index, E element);:向集合中指定位置插入元素

  3. boolean addAll(Collection<? extends E> c);:向集合中添加c集合的所有元素,将c集合中的所有元素添加到此集合中

    1. c:Collection以及子孙类都可以,集合参数

  4. boolean addAll(int index, Collection<? extends E> c);:向集合中指定位置插入c集合的所有元素

  5. E get(int index);:获取集合中指定位置的元素

  6. boolean contains(Object o);:判断集合中是否包含指定元素

  7. boolean containsAll(Collection<?> c);:判断集合中是否包含指定集合的元素

  8. int indexOf(Object o);:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1

  9. int lastIndexOf(Object o);:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1

  10. boolean remove(Object o);:从集合中移除指定元素

  11. E remove(int index);:通过下标索引删除集合中的元素

  12. boolean removeAll(Collection<?> c);:从集合中移除c集合的所有相同元素

  13. E set(int index, E element);:修改指定下标索引的元素

  14. default void sort(Comparator<? super E> c):通过比较器给集合排序

  15. List<E> subList(int fromIndex, int toIndex);:通过指定起始位置以及结束位置裁剪集合

  16. boolean equals(Object o);:判断集合是否相同

  17. Object[] toArray();:将集合转为数组

  18. int size();:返回集合长度(元素数量)

  19. void clear();:清空集合(将所有元素删除)

  20. boolean isEmpty();:判断集合是否为空(不是null)

  21. Iterator<E> iterator();:返回集合可迭代对象

  22. default Stream<E> stream():返回集合的Stream流

  23. public synchronized void addElement(E obj):向集合中添加元素,不返回任何内容

  24. public synchronized int capacity():返回当前集合中的数组长度,注意与size不同,size是返回元素个数

  25. public synchronized E firstElement():获取集合中的第一个元素

  26. public synchronized E lastElement():获取集合中的最后一个元素

  27. public synchronized boolean removeElement(Object obj):移除集合中的指定元素

  28. public synchronized void setSize(int newSize):设置集合长度

4. Vector代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建Vector对象
        Vector vector = new Vector();
        // 1. `boolean add(E e);`:向集合中添加新的元素
        System.out.println("============================add============================");
        vector.add("梅超风");
        vector.add("何仙姑");
        vector.add("张道陵");
        vector.add("张友人");
        vector.add("张百忍");
        vector.add("玉皇大帝");
        vector.add(1.23);
        vector.add(1, "玉皇大帝");
        System.out.println(vector);
        // 5. `E get(int index);`:获取集合中指定位置的元素
        System.out.println("============================get============================");
        Object o = vector.get(2);
        System.out.println(o);
        // 6. `boolean contains(Object o);`:判断集合中是否包含指定元素
        System.out.println("============================contains============================");
        boolean isContains = vector.contains("张友人");
        System.out.println(isContains);
        // 8. `int indexOf(Object o);`:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("============================indexOf============================");
        int indexOf = vector.indexOf("玉皇大帝");
        System.out.println(indexOf);
        // 9. `int lastIndexOf(Object o);`:判断集合中是否存在指定元素(只判断最后一次出点的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("============================lastIndexOf============================");
        int lastIndexOf = vector.lastIndexOf("玉皇大帝");
        System.out.println(lastIndexOf);
        // 10. `boolean remove(Object o);`:从集合中移除指定元素
        System.out.println("============================remove============================");
        boolean remove = vector.remove(1.23);
        System.out.println(remove);
        System.out.println(vector);
        // 13. `E set(int index, E element);`:修改指定下标索引的元素
        System.out.println("============================set============================");
        Object oldValue = vector.set(0, "元始天尊");
        System.out.println(oldValue);
        System.out.println(vector);
        // 17. `Object[] toArray();`:将集合转为数组
        System.out.println("============================toArray============================");
        Object[] objects = vector.toArray();
        System.out.println(Arrays.toString(objects));
        // 18. `int size();`:返回集合长度(元素数量)
        System.out.println("============================size============================");
        int size = vector.size();
        System.out.println(size);
        // 19. `void clear();`:清空集合(将所有元素删除)
        System.out.println("============================isEmpty============================");
        System.out.println(vector.isEmpty());
        // 23. `public synchronized void addElement(E obj)`:向集合中添加元素,不返回任何内容
        System.out.println("============================addElement============================");
        vector.addElement("猪刚鬣");
        System.out.println(vector);
        // 24. `public synchronized int capacity()`:返回当前集合中的数组长度,注意与size不同,size是返回元素个数
        System.out.println("============================capacity============================");
        int capacity = vector.capacity();
        System.out.println(capacity);
        // 25. `public synchronized E firstElement()`:获取集合中的第一个元素
        System.out.println("============================firstElement============================");
        Object o1 = vector.firstElement();
        System.out.println(o1);
        // 26. `public synchronized E lastElement()`:获取集合中的最后一个元素
        System.out.println("============================lastElement============================");
        Object o2 = vector.lastElement();
        System.out.println(o2);
        // 27. `public synchronized boolean removeElement(Object obj)`:移除集合中的指定元素
        System.out.println("============================removeElement============================");
        boolean isRemoveElement = vector.removeElement("猪刚鬣");
        System.out.println(isRemoveElement);
        System.out.println(vector);
        // 28. `public synchronized void setSize(int newSize)`:设置集合长度
        System.out.println("============================setSize============================");
        System.out.println("调用setSize前");
        System.out.println(vector.size());
        System.out.println(vector.capacity());
        vector.setSize(50);
        System.out.println("调用setSize后");
        System.out.println(vector.size());
        System.out.println(vector.capacity());
    }
}
5. ArrayList/LinkedList/Vector总结(重点看区别)
1. ArrayList/LinkedList/Vector的区别(重点)
  1. ArrayList:底层是基于数组实现(动态数组),增删慢,查询快,线程不安全-->ArrayList常用

    1. 数组增删时需要将当前位置之后的数据要么整体向前移,要么整体向后移,所以增加删除速度慢

    2. 数组查询速度快原因是可以指定下标索引直接取值

  2. LinkedList:底层是基于双向链表实现,增删快,查询慢,线程不安全

    1. 双链表中的节点对象只需要记住他的前一个Node节点以及后一个Node节点,所以增删是不需要移动位置,只需要重新设置指向即可所以增删速度快

    2. 双链表查询速度慢是因为不能通过下标索引直接取值,只能从第一个遍历到最后一个节点对象(Java使用了二分查,所以速度相对快一点)

  3. Vector:底层是基于数组实现(动态数组),增删慢,查询快,线程安全

2. ArrayList/LinkedList/Vector的创建对象的方式

由于他们都属于是List接口的直接子类,所以一般创建对象时都是通过多态方式(父类引用指向子类),所以所有的单独方法都无法使用 多态方式创建List集合对象

List list = new ArrayList(); List list = new LinkedList(); List list = new Vector();

3. ArrayList/LinkedList/Vector的统一常用方法(掌握)
  1. boolean add(E e);:向集合中添加新的元素

  2. boolean addAll(int index, Collection<? extends E> c);:向集合中指定位置插入c集合的所有元素

  3. E get(int index);:获取集合中指定位置的元素

  4. int indexOf(Object o);:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1

  5. boolean remove(Object o);:删除集合中的指定元素

  6. E set(int index, E element);:修改指定下标索引的元素

  7. int size():获取集合中元素的个数

  8. boolean isEmpty():判断集合是否为空

  9. boolean contains(Object o):判断集合中是否包含指定元素

  10. Iterator<E> iterator():获取集合中迭代器对象

4. ArrayList/LinkedList/Vector的统一常用方法代码案例
public class Demo {
    public static void main(String[] args) {
        // 多态方式创建三个集合对象
        List arrayList = new ArrayList();
        List linkedList = new LinkedList();
        List vector = new Vector();
        // 1. `boolean add(E e);`:向集合中添加新的元素
        System.out.println("===========================add===========================");
        arrayList.add("张百忍");
        arrayList.add("玉皇大帝");
        arrayList.add("王母娘娘");
        arrayList.add("猪刚鬣");
        arrayList.add("卷门帘子");
        arrayList.add("月老");
        System.out.println(arrayList);
        linkedList.add("张百忍");
        linkedList.add("玉皇大帝");
        linkedList.add("王母娘娘");
        linkedList.add("猪刚鬣");
        linkedList.add("卷门帘子");
        linkedList.add("月老");
        System.out.println(linkedList);
        vector.add("张百忍");
        vector.add("玉皇大帝");
        vector.add("王母娘娘");
        vector.add("猪刚鬣");
        vector.add("卷门帘子");
        vector.add("月老");
        System.out.println(vector);
        // 2. `boolean addAll(int index, Collection<? extends E> c);`:向集合中指定位置插入c集合的所有元素
        System.out.println("===========================addAll===========================");
        // 3. `E get(int index);`:获取集合中指定位置的元素
        System.out.println("===========================get===========================");
        Object o1 = arrayList.get(1);
        Object o2 = linkedList.get(1);
        Object o3 = vector.get(1);
        System.out.println(o1);
        System.out.println(o2);
        System.out.println(o3);
        // 4. `int indexOf(Object o);`:判断集合中是否存在指定元素(只判断第一次出现的),并返回此元素的下标索引位置,如果没有找到则返回-1
        System.out.println("===========================indexOf===========================");
        int indexOf1 = arrayList.indexOf("卷门帘子");
        int indexOf2 = linkedList.indexOf("卷门帘子");
        int indexOf3 = vector.indexOf("卷门帘子");
        System.out.println(indexOf1);
        System.out.println(indexOf2);
        System.out.println(indexOf3);
        // 5. `boolean remove(Object o);`:删除集合中的指定元素
        System.out.println("===========================remove===========================");
        boolean isRemove1 = arrayList.remove("猪刚鬣");
        boolean isRemove2 = linkedList.remove("猪刚鬣");
        boolean isRemove3 = vector.remove("猪刚鬣");
        System.out.println(isRemove1);
        System.out.println(isRemove2);
        System.out.println(isRemove3);
        System.out.println(arrayList);
        System.out.println(linkedList);
        System.out.println(vector);
        // 6. `E set(int index, E element);`:修改指定下标索引的元素
        System.out.println("===========================set===========================");
        Object oldValue1 = arrayList.set(0, "张友人");
        Object oldValue2 = linkedList.set(0, "张友人");
        Object oldValue3 = vector.set(0, "张友人");
        System.out.println(oldValue1);
        System.out.println(oldValue2);
        System.out.println(oldValue3);
        System.out.println(arrayList);
        System.out.println(linkedList);
        System.out.println(vector);
        // 7. `int size()`:获取集合中元素的个数
        System.out.println("===========================size===========================");
        int size1 = arrayList.size();
        int size2 = linkedList.size();
        int size3 = vector.size();
        System.out.println(size1);
        System.out.println(size2);
        System.out.println(size3);
        // 8. `boolean isEmpty()`:判断集合是否为空
        System.out.println("===========================isEmpty===========================");
        boolean empty1 = arrayList.isEmpty();
        boolean empty2 = linkedList.isEmpty();
        boolean empty3 = vector.isEmpty();
        System.out.println(empty1);
        System.out.println(empty2);
        System.out.println(empty3);
        // 9. `boolean contains(Object o)`:判断集合中是否包含指定元素
        System.out.println("===========================contains===========================");
        boolean isContains1 = arrayList.contains("玉皇大帝");
        boolean isContains2 = linkedList.contains("玉皇大帝");
        boolean isContains3 = vector.contains("玉皇大帝");
        System.out.println(isContains1);
        System.out.println(isContains2);
        System.out.println(isContains3);
    }
}

3. 泛型(重点)

1. 泛型概述

泛型是在JDK1.5后添加的,泛型用于帮助我们建立更加安全的集合,使用了泛型后不必再进行强制类型转换(也不会出现类型转换异常) JDK提供了支持泛型的编译器,将运行时的类型检查提前到了编译时执行-->泛型,就是用于规范(规定)数据类型,让数据类型统一 使用泛型可以让代码的可读性和安全性更高

2. 集合中的泛型(重点)

定义集合时如果不添加泛型则集合中什么元素都可以添加,泛型在集合中的作用就是用于限制集合中可以添加数据有哪些,限制后则不可以随意添加数据 集合中使用泛型也是确保使用集合的安全性,以及可读性 集合中使用泛型格式:List<泛型类型> list = new List集合子类<>();

泛型类型:代表集合中可以使用的类型是什么,支持引用数据类型

1. 集合中泛型的使用代码案例
public class Demo {
    public static void main(String[] args) {
        // 集合中的泛型定义使用
        List<String> list = new ArrayList<>();
        // 添加数据
        boolean isAdd = list.add("安倍晋三");
        System.out.println(isAdd);
        System.out.println(list);
        list.add("卒于2022-07-08");
        System.out.println(list);
        // 获取数据
        String value = list.get(0);
        System.out.println(value);
        // 添加实体类数据
        List<People> peopleList = new ArrayList<>();
        // 添加数据
        peopleList.add(new People("小龙女", "龙", 18));
        peopleList.add(new People("杨过", "男", 18));
        peopleList.add(new People("白素贞", "母", 18));
        peopleList.add(new People("许仙", "男", 18));
        System.out.println(peopleList);
        // 获取数据
        People people = peopleList.get(1);
        System.out.println(people);
        // 集合中的泛型可以嵌套-->List集合套一个List集合(俄罗斯套娃)
        List<List<String>> lists = new ArrayList<>();
        // 添加数据
        // 定义新的List集合用于添加元素
        List<String> stringList = new ArrayList<>();
        List<Integer> integerList = new ArrayList<>();
        // 添加String数据
        stringList.add("嬴政");
        stringList.add("焊武帝");
        stringList.add("刘邦");
        stringList.add("项羽");
        // 添加Integer集合数据
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
        integerList.add(4);
        // 向List集合中添加List集合数据
        lists.add(stringList);
        lists.add(stringList);
        lists.add(stringList);
        lists.add(stringList);
        // 输出结果
        System.out.println(lists);
    }
}

以上是集合中使用泛型的案例,但是一般很少会出现嵌套List形式,并且就算是嵌套也不能超过2层

3. 泛型擦除补偿

Java的运行分为两个部分,编译运行两个部分,泛型的出现是提高了编译期的安全性,由于在编译期已经确定了类型,那么运行时则不会重新检查(不检测数据的类型) 泛型擦除则是在运行期间体现,一旦运行后则将泛型擦除(原本定义的泛型全部失效),所有的类型都为Object,这个过程就是泛型擦除补偿 泛型在编译期用于确保程序的安全性,但是在运行期则会将泛型去除(擦除),重新更改为Object类型

4. 泛型的定义以及使用(重点)
1. 泛型的定义概述

上面学完了集合中使用泛型,但是我们还不到如何定义泛型,泛型定义时的注意事项有哪些,泛型支持自定义(自己创建的类也可以使用泛型类型) 泛型可以在类,方法,接口,属性中使用

2. 泛型定义的格式
1. 泛型在类上定义格式

泛型在类上定义

修饰符 class 类名<定义泛型类型变量>{
    // 类的属性方法等
}

代码案例

/**
 * 定义泛型类
 *
 * @param <T> T-->type,泛型的类型,代表定义泛型变量
 *            String name-->定义了字符串变量
 */
public class GenericsClass<T> {
    // 属性中使用泛型类型
    private T t;

    public GenericsClass() {
    }

    // 形参使用泛型类型
    public GenericsClass(T t) {
        this.t = t;
    }

    // 返回值使用泛型类型
    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        // 创建自定义的泛型类
        // 一下两个相同
        // GenericsClass genericsClass = new GenericsClass();
        // List list = new ArrayList<>();
        // 创建自定义泛型类,指定泛型类型为String
        GenericsClass<String> genericsClass1 = new GenericsClass<>();
        // 创建自定义泛型类,指定泛型类型为Integer
        GenericsClass<Integer> genericsClass2 = new GenericsClass<>();
        // 设置数据
        // 由于使用了泛型类型,所以只能设置String类型数据
        genericsClass1.setT("彭于晏");
        // 由于使用了泛型类型,所以只能设置Integer类型数据
        genericsClass2.setT(185);
    }
}

以上是定义泛型类以及使用的过程 注意:带有尖括号(<>)则代表是定义泛型类型变量,不带尖括号(<>)则代表是使用泛型变量

 

2. 泛型在方法上定义

泛型在方法中定义方式

修饰符 <定义泛型变量> 返回值类型 (形参列表){
    // 方法体
}

泛型方法的定义

public class GenericsMethod {

    /**
     * 在方法中定义泛型类型
     *
     * @param t   形参为泛型类型参数(传入的参数是什么就是什么类型)
     * @param <T> 定义泛型变量
     */
    public static <T> void method01(T t) {
        // 输出传入的参数以及参数类型
        System.out.println("传入的参数为:" + t);
        // getClass()方法用于获取数据的类型(当前类的类型)
        System.out.println("参数类型为:" + t.getClass());
    }

    /**
     * 方法中定义泛型类型并使用
     *
     * @param t   形参为泛型类型参数(传入的参数是什么就是什么类型)
     * @param <T> 定义泛型变量
     * @return 返回值也是泛型类型
     */
    public static <E> E method02(E t) {
        // 输出传入的参数以及参数类型
        System.out.println("传入的参数为:" + t);
        // getClass()方法用于获取数据的类型(当前类的类型)
        System.out.println("参数类型为:" + t.getClass());
        // 泛型类型返回值不是代表可以随意返回任意类型,而是必须返回的类型与泛型变量相同
        // 说到底就是只能返回泛型类型的返回值
        return t;
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        // 使用方法中定义的泛型
        // 当传入字符串类型时方法的泛型类型就被确认了
        GenericsMethod.method01("彭于晏");
        // 当传入字符串类型时方法的泛型类型就被确认了,所以返回值直接返回的就是String类型
        String resultValue = GenericsMethod.method02("彭于晏");
        // 输出结果
        System.out.println(resultValue);
    }
}
3. 接口中定义泛型类型

接口中定义泛型类型时在实现接口时,类上也可以定义泛型,并且可以与接口的泛型通用(可以将类上定义的泛型变量当做参数传给接口),也可以在实现时定义接口的泛型类型 使用方式1 接口定义

/**
 * 泛型接口
 *
 * @param <T> 定义泛型变量
 */
public interface GenericsInterface<T> {
    /**
     * 泛型方法
     *
     * @param t 使用接口中定义的泛型变量当做形参
     */
    void func(T t);
}

实现类定义

/**
 * 实现泛型接口时可以指定泛型类型,指定后重写的方法也会是相同类型
 */
public class ImplementsClass01 implements GenericsInterface<String> {
    /**
     * 重写泛型接口方法
     *
     * @param s 形参列表,类型为使用泛型接口时定义的String类型
     */
    @Override
    public void func(String s) {
        System.out.println("传入的类型为:" + s.getClass());
        System.out.println("参数为:" + s);
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        // 泛型接口实现类1
        ImplementsClass01 implementsClass01 = new ImplementsClass01();
        // 调用方法
        implementsClass01.func("传入参数");
    }
}

使用方式2 接口定义

/**
 * 泛型接口
 *
 * @param <T> 定义泛型变量
 */
public interface GenericsInterface<T> {
    /**
     * 泛型方法
     *
     * @param t 使用接口中定义的泛型变量当做形参
     */
    void func(T t);
}

实现类定义

/**
 * 自定义类实现泛型接口时不指定泛型类型,而是定义一个泛型变量,将泛型变量当做参数传给接口
 *
 * @param <T> 定义泛型变量
 */
public class ImplementsClass02<T> implements GenericsInterface<T> {
    /**
     * 重写泛型接口方法
     *
     * @param t 使用接口中定义的泛型变量当做形参
     */
    @Override
    public void func(T t) {
        System.out.println("传入的类型为:" + t.getClass());
        System.out.println("参数为:" + t);
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        // 泛型接口实现类2
        ImplementsClass02<Integer> implementsClass02 = new ImplementsClass02<>();
        // 调用方法
        implementsClass02.func(123);
    }
}
5. 泛型通配符(熟悉)
1. 泛型通配符概述

泛型是用于限定数据类型,当集合或自定义类中使用泛型时可以明确泛型的数据类型,那么使用时只能传输给定的数据类型,否则会出现错误 在实际开发中可能会出现在定义方法时,根本无法确定具体的数据类型是什么,为了解决这个不确定性泛型提供了通配符供我们使用

2. 泛型通配符分类
1. 无限定通配符:<?>-->任意泛型类型都可以
2. 上限通配符:<? extends 泛型类型>-->只允许泛型类型及其子孙类

如果泛型类型为:String类型,参数则必须是String类型或者其子孙类型

3. 下限通配符:<? supper 泛型类型>-->只允许泛型类型及其父类

如果泛型类型为:String类型,参数则必须是String类型或者其父类

3. 泛型通配符代码案例
创建类的父子关系

爷爷类

public class YeClass {
}

父亲类

/**
 * 父类继承爷爷类
 */
public class FuClass extends YeClass {
}

子孙类

/**
 * 子类继承父类
 */
public class ZiClass extends FuClass{
}
1. 无限定通配符
public class Demo {
    public static void main(String[] args) {
        // 定义集合类型
        List<String> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        List<ZiClass> list3 = new ArrayList<>();
        // 调用方法,func00的方法参数为List<String>类型,已经写死必须只能传入此类型,其他类型则不行
        func00(list1);
        // 传入其他List集合类型
        // func00(list2);
        // 使用无限定通配符传入参数,允许任意List集合的参数类型
        func01(list1);
        func01(list2);
        func01(list3);
    }

    /**
     * 限定泛型类型方法
     *
     * @param list 形参
     */
    public static void func00(List<String> list) {
        System.out.println(list);
    }

    /**
     * 无限定泛型类型方法
     *
     * @param list 形参
     */
    public static void func01(List<?> list) {
        System.out.println(list);
    }
}
2. 上限通配符
public class Demo {
    public static void main(String[] args) {
        // 调用上限通配符方法
        // 定义集合
        // 祖宗类
        List<YeClass> yeClasses = new ArrayList<>();
        // 父类
        List<FuClass> fuClasses = new ArrayList<>();
        // 子孙类
        List<ZiClass> ziClasses = new ArrayList<>();
        // 传入祖宗类,不允许
        // func02(yeClasses);
        // 传入父类允许
        func02(fuClasses);
        // 传入子类允许
        func02(ziClasses);
    }
    
    /**
     * 上限通配符,只支持FuClass及其子孙类
     *
     * @param list 形参
     */
    public static void func02(List<? extends FuClass> list) {
        System.out.println(list);
    }
}
3. 下限通配符
public class Demo {
    public static void main(String[] args) {

        // 创建集合对象
        // 祖宗类
        List<YeClass> yeClasses = new ArrayList<>();
        // 父类
        List<FuClass> fuClasses = new ArrayList<>();
        // 子孙类
        List<ZiClass> ziClasses = new ArrayList<>();
        // 调用下限通配符方法
        // 传入父类允许
        func03(yeClasses);
        // 传入本类允许
        func03(fuClasses);
        // 传入子孙类不允许
        // func03(ziClasses);
    }
    /**
     * 下限通配符,只支持FuClass及其父类
     *
     * @param list 形参
     */
    public static void func03(List<? super FuClass> list) {
        System.out.println(list);
    }
}

4. 迭代器(掌握)

1. Iterator迭代器
1. Iterator概述

Iterator迭代器一般用于集合迭代,迭代器中存储的是集合元素,与集合类似,都会存储数据,但是存储的方式不同,一般只要取出集合元素通过通用方式遍历都会用到迭代器 Iterator迭代器是一种集合通用遍历方式,这样针对Collection集合的遍历更加简单更加统一,并且能达到逻辑代码与具体实现相分类的效果(解耦效果) Collection集合中通用的获取方式都是使用Iterator<E> iterator()方法获取,通用获取方式,但是每个集合中也会有自己独立的获取,但是一般只要使用多态方式获取基本用统一的获取方式即可

2. Iterator集合获取方式

Collection集合通用获取方式,调用集合的Iterator<E> iterator()方法获取 例如:

// 定义集合类型
List<泛型类型> list = new 集合实现类();
// 获取Iterator迭代器方法
Iterator iterator = list.iterator();
3. Iterator常用方法
  1. boolean hasNext():用于判断迭代器中是否有下一个元素

  2. E next():指向迭代器中的下一个元素,每次调用next都会记录当前指向的位置

  3. default void remove():从迭代器中移除一个next指向的元素,如果next的指向不是元素则会报异常

4. Iterator代码案例
public class Demo {
    public static void main(String[] args) {
        // 定义集合
        List<String> list = new ArrayList<>();
        // 添加数据
        list.add("梅超风");
        list.add("秦始皇");
        list.add("基尼太美");
        list.add("裘千尺");
        // 输出结果
        System.out.println(list);
        // 获取迭代器,通过调用iterator方法,返回迭代器对象
        Iterator<String> iterator = list.iterator();
        // 调用迭代器方法
        // 1. `boolean hasNext()`:用于判断迭代器中是否有下一个元素
        System.out.println("============================hasNext============================");
        boolean hasNext = iterator.hasNext();
        System.out.println(hasNext);
        // 2. `E next()`:指向迭代器中的下一个元素
        System.out.println("============================next============================");
        // 当next指向下一个元素时会将元素返回
        /*String next = iterator.next();
        System.out.println(next);
        hasNext = iterator.hasNext();
        System.out.println(hasNext);
        next = iterator.next();
        System.out.println(next);
        hasNext = iterator.hasNext();
        System.out.println(hasNext);
        next = iterator.next();
        System.out.println(next);
        hasNext = iterator.hasNext();
        System.out.println(hasNext);
        next = iterator.next();
        System.out.println(next);
        hasNext = iterator.hasNext();
        System.out.println(hasNext);
        next = iterator.next();
        System.out.println(next);*/
        // 使用hasNext与next结合的方式遍历Iterator迭代器数据
        while (iterator.hasNext()) {
            // 在循环内调用next方法,用于指向下一个元素
            String next = iterator.next();
            // 判断当前数据是否为基尼太美,如果是则删除
            if ("基尼太美".equals(next)) {
                // 移除迭代器元素
                iterator.remove();
            }
            System.out.println(next);
        }
        // 打印List集合数据,List集合中的数据也被移除了,Iterator迭代的就是List的数据
        System.out.println(list);
        // 3. `default void remove()`:从迭代器中移除一个元素
        System.out.println("============================remove============================");
    }
}

Iterator迭代器用于遍历集合中的数据,并且所有操作与List集合都有关联,例如Iterator迭代器的移除方法,移除后List集合的数据也会被移除

2. ListIterator迭代器(了解熟悉)
1. ListIterator概述

ListIterator是Iterator的子接口,但是比Iterator更加强大(多了一些方法),提供的这些方法让ListIterator使用起来更加方便

2. ListIterator获取方式

通过List集合方法获取:

// 定义集合
List<泛型类型> list = new 集合类型<>();
// 获取ListIterator迭代器
ListIterator<泛型类型> listIterator = list.listIterator();
3. ListIterator常用方法
  1. boolean hasNext():用于判断迭代器中是否有下一个元素

  2. E next():指向迭代器中的下一个元素,每次调用next都会记录当前指向的位置

  3. default void remove():从迭代器中移除一个next指向的元素,如果next的指向不是元素则会报异常

  4. boolean hasPrevious():用于逆向遍历集合,判断迭代器前面是否存在元素

  5. E previous():指向迭代器中的前一个元素,每次调用previous都会记录当前指向的位置

  6. void set(E e):从迭代器中将指定的next或previous返回的元素更改为指定元素

  7. void add(E e):将指定元素插入之集合中,插入位置是当前迭代器迭代的位置之前

4. ListIterator代码案例
public class Demo {
    public static void main(String[] args) {
        // 定义集合
        List<String> list = new ArrayList<>();
        // 添加数据
        list.add("梅超风");
        list.add("秦始皇");
        list.add("基尼太美");
        list.add("裘千尺");
        list.add("安倍晋三");
        // 输出结果
        System.out.println(list);
        // 获取ListIterator迭代器
        ListIterator<String> listIterator = list.listIterator();
        // 1. `boolean hasNext()`:用于判断迭代器中是否有下一个元素
        // 2. `E next()`:指向迭代器中的下一个元素,每次调用next都会记录当前指向的位置
        /*while (listIterator.hasNext()) {
            // 调用next方法返回元素
            String next = listIterator.next();
            System.out.println(next);
        }*/
        System.out.println("=========================");
        // 3. `default void remove()`:从迭代器中移除一个next指向的元素,如果next的指向不是元素则会报异常
        // 4. `boolean hasPrevious()`:用于逆向遍历集合,判断迭代器前面是否存在元素
        // 5. `E previous()`:指向迭代器中的前一个元素,每次调用previous都会记录当前指向的位置
        /*while (listIterator.hasPrevious()) {
            // 调用previous方法返回元素
            String previous = listIterator.previous();
            System.out.println(previous);
        }*/
        /*while (true) {
            while (listIterator.hasNext()) {
                // 调用next方法返回元素
                String next = listIterator.next();
                System.out.println(next);
            }
            while (listIterator.hasPrevious()) {
                // 调用previous方法返回元素
                String previous = listIterator.previous();
                System.out.println(previous);
            }
        }*/
        // 6. `void set(E e)`:从迭代器中将指定的next或previous返回的元素更改为指定元素
        // listIterator.next();
        // listIterator.set("石榴姐");
        // System.out.println(list);
        // 7. `void add(E e)`:将指定元素插入之集合中,插入位置是当前迭代器迭代的位置之前
        listIterator.add("石榴姐");
        System.out.println(list);
    }
}

5. Map接口(重点)

1. Map接口概述

现实生活中我们经常存储一些信息例如身份证:身份证号对应姓名,微信:一个手机号对应一个微信号,夫妻:一夫一妻 Map集合的存储方式就是一一对应的方式-->key=value-->对应-->键值对 例如:身份证号与姓名的对应-->key=身份证号,value=姓名 Map集合中的key不允许重复,value允许重复 语法格式:key=value

2. Map接口常用方法
  1. V put(K key, V value):向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)

  2. V get(Object key):通过指定key获取value值

  3. default V getOrDefault(Object key, V defaultValue):通过key获取value值,如果此key不存在则使用默认值输出

  4. V remove(Object key):通过指定key移除key和value

  5. boolean containsKey(Object key):判断Map集合中是否包含指定key

  6. boolean containsValue(Object value):判断集合中是否包含指定value

  7. Collection<V> values():返回Map集合中的所有value值

  8. Set<K> keySet():返回Map集合中的所有key值

  9. Set<Map.Entry<K, V>> entrySet():返回Map集合中的所有key-value值(返回所有键值对)

  10. int size():返回Map集合中的key-value数量

  11. void clear():清空Map集合所有元素

  12. boolean isEmpty():判断Map集合是否为空

3. Map接口实现类
1. Map接口之实现类概述

由于Map属于接口,所以无法直接创建对象,只能通过其子孙类创建对象,子孙类中只需要知道4个类即可,并且实现类实现了Map接口的方法,并且方法基本通用

2. Map接口之HashMap实现类(重点)
1. HashMap类概述(理解)

HashMap底层是采用哈希算法实现,是Map接口最常用的实现类,由于底层采用哈希算法所以它存储方式要求不允许出现重复的数据,哈希算法又被称之为哈希表,所以可以称HashMap底层由哈希表组成,但是注意,JDK1.8后HashMap集合底层除了哈希表之外还会使用红黑树作为数据存储 注意:JDK1.8中的HashMap集合在存储数据长度为8之前采用哈希表存储,长度超过8时改为红黑树存储 哈希表的组成:链表+数组-->解决了数组和链表的共性问题,哈希表的速度会提升很大 HashMap的底层使用的数据类型比较多,且会解决很大的效率问题

2. HashMap构造方法
// 使用空参构造方法创建HashMap对象
public HashMap() {
    // 创建HashMap对象时赋值默认长度
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
// 创建HashMap对象并指定初始化容量
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
// 创建HashMap对象并指定Map集合数据,添加至Map集合
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}
3. HashMap常用方法
  1. V put(K key, V value):向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)

  2. V get(Object key):通过指定key获取value值

  3. default V getOrDefault(Object key, V defaultValue):通过key获取value值,如果此key不存在则使用默认值输出

  4. V remove(Object key):通过指定key移除key和value

  5. boolean containsKey(Object key):判断Map集合中是否包含指定key

  6. boolean containsValue(Object value):判断集合中是否包含指定value

  7. Collection<V> values():返回Map集合中的所有value值

  8. Set<K> keySet():返回Map集合中的所有key值

  9. Set<Map.Entry<K, V>> entrySet():返回Map集合中的所有key-value值(返回所有键值对)

    1. 返回值为Set集合,Set集合中有一个Entry接口,其中包含了获取Key和Value的方法

      1. K getKey():获取Entry中的key值

      2. V getValue():获取Entry中的value值

  10. int size():返回Map集合中的key-value数量

  11. void clear():清空Map集合所有元素

  12. boolean isEmpty():判断Map集合是否为空

4. HashMap代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建HashMap集合对象
        HashMap<String, String> idCard = new HashMap<>();
        // 设置数据
        // 1. `V put(K key, V value)`:向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)
        System.out.println("====================put====================");
        idCard.put("20021230", "彭于晏");
        idCard.put("20021231", "鞠婧祎");
        idCard.put("15000203", "天山童姥");
        idCard.put("10000203", "弼马温");
        idCard.put("16000509", "黑山老妖");
        idCard.put("14000909", "鲲");
        System.out.println(idCard);
        idCard.put("14000909", "基尼太美");
        System.out.println(idCard);
        // 2. `V get(Object key)`:通过指定key获取value值
        System.out.println("====================get====================");
        String value = idCard.get("基尼太美");
        System.out.println(value);
        value = idCard.get("14000909");
        System.out.println(value);
        // 3. `default V getOrDefault(Object key, V defaultValue)`:通过key获取value值,如果此key不存在则使用默认值输出
        System.out.println("====================getOrDefault====================");
        String valueDefault = idCard.getOrDefault("基尼太美", "暂无数据");
        System.out.println(valueDefault);
        // 4. `V remove(Object key)`:通过指定key移除key和value
        System.out.println("====================remove====================");
        String removeValue = idCard.remove("10000203");
        System.out.println(removeValue);
        System.out.println(idCard);
        // 5. `boolean containsKey(Object key)`:判断Map集合中是否包含指定key
        System.out.println("====================containsKey====================");
        boolean containsKey = idCard.containsKey("14000909");
        System.out.println(containsKey);
        containsKey = idCard.containsKey("140009091");
        System.out.println(containsKey);
        // 6. `boolean containsValue(Object value)`:判断集合中是否包含指定value
        System.out.println("====================containsValue====================");
        boolean containsValue = idCard.containsValue("基尼太美");
        System.out.println(containsValue);
        containsValue = idCard.containsValue("基尼太美1");
        System.out.println(containsValue);
        // 7. `Collection<V> values()`:返回Map集合中的所有value值
        System.out.println("====================values====================");
        Collection<String> values = idCard.values();
        System.out.println(values);
        // 8. `Set<K> keySet()`:返回Map集合中的所有key值
        System.out.println("====================keySet====================");
        Set<String> keySet = idCard.keySet();
        System.out.println(keySet);
        // 获取Set集合迭代器
        Iterator<String> iterator = keySet.iterator();
        // 使用while循环输出Iterator迭代器数据
        while (iterator.hasNext()) {
            // 指向迭代器下一条记录并返回结果
            String key = iterator.next();
            System.out.println(key + ":" + idCard.get(key));
        }
        // 9. `Set<Map.Entry<K, V>> entrySet()`:返回Map集合中的所有key-value值(返回所有键值对)
        System.out.println("====================entrySet====================");
        Set<Map.Entry<String, String>> entries = idCard.entrySet();
        Iterator<Map.Entry<String, String>> iterator1 = entries.iterator();
        // while循环遍历迭代器
        while (iterator1.hasNext()) {
            Map.Entry<String, String> entry = iterator1.next();
            // Entry中的getKey和getValue方法用于获取键和值
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        // 10. `int size()`:返回Map集合中的key-value数量
        System.out.println("====================size====================");
        int size = idCard.size();
        System.out.println(size);
        // 11. `void clear()`:清空Map集合所有元素
        System.out.println("====================clear====================");
        idCard.clear();
        // 12. `boolean isEmpty()`:判断Map集合是否为空
        System.out.println("====================isEmpty====================");
        boolean empty = idCard.isEmpty();
        System.out.println(empty);
        // 添加数据
        idCard.put("20200709", "添加数据");
        empty = idCard.isEmpty();
        System.out.println(empty);
    }
}
3. HashMap的put方法源码分析(了解)
// -->HashMap底层存储数据的格式,代表哈希表结构
transient Node<K,V>[] table;

// putVal方法,设置值方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    // 数组类型Node节点-->哈希表
    Node<K,V>[] tab;
    // Node节点-->链表结构
    Node<K,V> p;
    // int整数型数据
    int n;
    int i;
    // (tab = table)将HhashMap的数据临时赋值给tab
    // (tab = table) == null-->再次验证tab是否等于null
    // (n = tab.length)将tab的length值赋值给变量n
    // (n = tab.length) == 0)-->再次验证长度是否为0
    if ((tab = table) == null || (n = tab.length) == 0)
        // 如果length长度为0则代表HashMap创建时为初始化容量,并且是没有数据的
        // 将原本的长度重新计算并重新赋值给变量n
        // resize()如果为null或为0运算的结果过为16-->数组的长度为16
        // tab = resize()-->等同于给tab临时变量重新赋值,并且初始化数组的长度为16
        n = (tab = resize()).length;
    // [i = (n - 1) & hash]-->最终的结果为n-1=16-1-->15,15 & hash-->等同于hash 取余 16
    // (p = tab[i = (n - 1) & hash])-->将tab临时HashMap的小表索引的数据取出,赋值给p临时变量
    // (p = tab[i = (n - 1) & hash]) == null-->如果p==null则代表此下标索引内没有数据
    if ((p = tab[i = (n - 1) & hash]) == null)
        // tab[i]-->i是上方运算出来的结果,当前小标索引的元素
        // newNode(hash, key, value, null);-->新建一个Node节点对象,并赋值给tab[i]下标索引
        // 小表索引数据为空时首次添加的逻辑
        tab[i] = newNode(hash, key, value, null);
    else {
        // 声明Node节点对象-->e
        Node<K,V> e;
        // 声明泛型变量K-->key
        K k;
        // p.hash == hash-->key值的hash计算结果,当前key与当前下标索引的key如果结果相同,则继续验证
        // 如果不同则走到else if
        // ((k = p.key) == key || (key != null && key.equals(k)))
        // (k = p.key) == key-->判断传入的key是否与上面取出的Node节点的key相同,如果相同则代表是同一个数据
        // 如果不同则继续验证
        // (key != null && key.equals(k))-->如果==验证为false则验证其内容是否相同,如果相同则进入if
        // 如果不同则执行else if
        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
            // 如果相同则将当前下标索引的p节点赋值给e节点
            e = p;
        // 判断取出的临时节点p是否是红黑树类型
        else if (p instanceof TreeNode)
            // 如果是红黑树则通过红黑树的判断验证赋值或覆盖value值
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            // 死循环
            for (int binCount = 0; ; ++binCount) {
                // (e = p.next) == null-->用于取出p节点的下一个指向的节点是否为null
                // 如果为null则直接赋值,如果不为空则继续循环
                if ((e = p.next) == null) {
                    // 将我们新加入的数据添加到next的指向
                    p.next = newNode(hash, key, value, null);
                    // static final int TREEIFY_THRESHOLD = 8;
                    // binCount >= TREEIFY_THRESHOLD - 1-->用于验证存储的数据是否超过或等于8个
                    if (binCount >= TREEIFY_THRESHOLD - 1) // 8-1=7
                        // 将哈希表转为红黑树
                        treeifyBin(tab, hash);
                    // 跳出循环
                    break;
                }
                // e.hash == hash-->key值的hash计算结果,当前key与当前下标索引的key如果结果相同,则继续验证
                // 如果不同则走到else if
                // ((k = e.key) == key || (key != null && key.equals(k)))
                // (k = p.key) == key-->判断传入的key是否与上面取出的Node节点的key相同,如果相同则代表是同一个数据
                // 如果不同则继续验证
                // (key != null && key.equals(k))-->如果==验证为false则验证其内容是否相同,如果相同则进入if
                // 如果不同则执行else if
                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                    // 跳出循环-->重新覆盖value值
                    break;
                // 将临时Node节点e重新赋值给临时Node节点p变量
                p = e;
            }
        }
        // (e != null)将e的node节点判断是否为空,如果不等于null则进入
        if (e != null) { // existing mapping for key
            // 将e临时节点变量中的值取出赋值给oldValue
            V oldValue = e.value;
            // onlyIfAbsent-->HashMap集合的put方法传入的始终都是false,取反后始终都是true
            if (!onlyIfAbsent || oldValue == null)
                // 将传入的value值赋值给当前e临时节点的value值
                e.value = value;
            // 将新修改的value值的Node节点重新赋值到table中
            afterNodeAccess(e);
            // 返回覆盖前的老值(oldValue
            return oldValue;
        }
    }
    // 修改的次数
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}
// HashMap的put方法中的hash方法的算法,以及取出数组元素的算法
public class Demo {
    public static void main(String[] args) {
        /*String str = "abc";
        Object obj = str;
        // 调用hashCode方法计算hashCode值
        int hashCode = obj.hashCode();
        System.out.println(hashCode);
        // (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        int i = hashCode ^ (hashCode >>> 16);
        System.out.println(hashCode >>> 16);
        System.out.println(Integer.toBinaryString(hashCode));
        System.out.println(Integer.toBinaryString(i));
        System.out.println(Integer.toBinaryString(hashCode >>> 16));
        // ^异或的二进制运算格式
        // 10111100001100010-->96354
        // 10111100001100001-->96353
        // 00000000000000001
        System.out.println(96354 ^ 96353);
        // 10111100001100010-->96354
        // 10111100001100001-->96353
        // 00000000000000011*/

        String str = "abc";
        Object obj = str;
        // hash值运算结果(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        // obj.hashCode等同于上面的这个运算key.hashCode()
        int hashCode = obj.hashCode();
        // 使用hashCode>>>16计算结果
        int i = hashCode >>> 16;
        System.out.println(hashCode + "----" + i);
        int hash = hashCode ^ i;
        System.out.println(hashCode + "^" + i + "=" + hash);
        System.out.println(str + "的hash值为:" + hash);
        // (n - 1) & hash-->算法结果
        // (n - 1)=15
        // 15 & hash-->值等同于取余16
        System.out.println(15 & hash);
        System.out.println(15 & 654184158);
        System.out.println(15 & 33);
    }
}
4. 二叉树和红黑树二叉树(了解)

二叉树是一种算法,通过算法得出结果,并且也是一种重要的数据类型-->基于底层数据类型

1. 二叉树的定义

二叉树是一种树形结构的类型,需要实际的问题抽象出来的数据结果往往都是二叉树的形式,即使是一半的树也能够简单的转换为二叉树,二叉树是基于链表结构,二叉树的存储结构以及算法较为简单(针对科学家)所以二叉树就显得特别重要 二叉树数据结构的形状是由一个节点以及两颗互不相交的树组成,分别成这两棵树为左子树和右子树,二叉树的树形结构分为五种样式

树形结构样式
第一种:空树,没有数据 第二种:仅有一个节点的二叉树 第三种:仅有左子树的二叉树 第四种:仅有右子树的二叉树 第五种:完整二叉树,带有左子树以及右子树 以上是二叉树的五种基本形态解释以及图解

2. 普通二叉树数据排列方式

左子树上的所有节点都比根节点小,右子树的所有节点都比根节点大 例如有这么一组数据:[15,12,14,23,5,16,13,18,4] 运算结果为
以上是二叉树的算法,基本排序,那么问题来了,如果数据是递增或递减,那么将有二叉树变为普通的链表结构

 

3. 平衡二叉树

为了避免二叉树出现的数据一边倒的情况,科学家提出了平衡二叉树理论 平衡二叉树中任何节点的两个子树的高度最大差别为1,一旦超出平衡高度则重新运算(重新评估整个二叉树的平衡) 例如最终结果不管是递增还是递减,其数据始终都会保持平衡 保持平衡的原因是由平衡二叉树中平衡因子(-1 0 1),使用平衡引子进行运算,运算后如果当前树一遍倾倒后会重新排列 排列方式就是通过左旋右旋方式,如果偏差向右则向左旋转,如果偏差向左则向右旋转 但是旋转时的次数未知-->需要根据数据量来计算统计(算法统计) 平衡二叉树出现的问题就是每次的缺失平衡后,他的旋转次数(排列次数)是未知的,会造成效率低的问题 例如有这么一组数据:[1,2,3,4,5,6,7,8,9]

 



以上是平衡二叉树排列的数据 平衡二叉树同样存在问题,数据量大时重新计算排列的次数不确定(不明确),有可能出现排列次数过多情况,影响效率

4. 红黑树

为了避免平衡二叉树出现的排列次数不明确的情况,科学家提出了红黑二叉树的理论 红黑树是有红色和黑色组成,且只有红和黑,同样黑红数也是一颗自平衡排序二叉树 红黑树的特征

特征1. 结点是红色或黑色。 特征2. 根结点是黑色,且永远都是黑色。 特征3. 所有叶子都是黑色。(叶子是null结点) 特征4. 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点) 特征5. 从任一结点到其每个叶子的所有路径都包含相同数量的黑色结点。 红黑树通过这些特征从根部延伸知道不平衡时重新计算,并且计算时会知道旋转次数 红黑树的基本操作

  1. 插入,2. 删除,3. 左旋,4. 右旋,5. 着色,每插入一条数据或删除一条数据,都可能会导致树的不平衡,从而自动进行左旋,右旋,着色操作,使红黑树平衡 红黑树演示网址:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html 例如有这么一组数据:[15,2,3,51,5,65,4,8,15,6,31,54,48,41,23]



     

5. Map接口之LinkedHashMap实现类(熟悉)
1. LinkedHashMap概述

LinkedHashMap是HashMap的集合的子集合,但是不再是单纯的哈希表组成,而是采用哈希表+链表结构,能够保证元素有序(存储顺序与取出顺序相同) LinkedHashMap类和HashMap类用法基本完全相同,LinkedHashMap集合中的Key也不允许重复,存储时允许为null,key也允许为null但是只能存在一个,如果出现key重复则覆盖value值

2. LinkedHashMap构造方法
// 空参构造方法,用于创建LinkedHashMap集合对象
public LinkedHashMap() {
    // 调用父类构造方法
    super();
    accessOrder = false;
}
// 创建LinkedHashMap对象并指定初始容量
public LinkedHashMap(int initialCapacity) {
    super(initialCapacity);
    accessOrder = false;
}
// 指定Map集合创建LinkedHashMap集合对象
public LinkedHashMap(Map<? extends K, ? extends V> m) {
    super();
    accessOrder = false;
    putMapEntries(m, false);
}
3. LinkedHashMap常用方法
  1. V put(K key, V value):向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)

  2. V get(Object key):通过指定key获取value值

  3. default V getOrDefault(Object key, V defaultValue):通过key获取value值,如果此key不存在则使用默认值输出

  4. V remove(Object key):通过指定key移除key和value

  5. boolean containsKey(Object key):判断Map集合中是否包含指定key

  6. boolean containsValue(Object value):判断集合中是否包含指定value

  7. Collection<V> values():返回Map集合中的所有value值

  8. Set<K> keySet():返回Map集合中的所有key值

  9. Set<Map.Entry<K, V>> entrySet():返回Map集合中的所有key-value值(返回所有键值对)

    1. 返回值为Set集合,Set集合中有一个Entry接口,其中包含了获取Key和Value的方法

      1. K getKey():获取Entry中的key值

      2. V getValue():获取Entry中的value值

  10. int size():返回Map集合中的key-value数量

  11. void clear():清空Map集合所有元素

  12. boolean isEmpty():判断Map集合是否为空

4. LinkedHashMap代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建LinkedHashMap对象
        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
        // 1. `V put(K key, V value)`:向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)
        System.out.println("======================put======================");
        linkedHashMap.put("chi", "小赤");
        linkedHashMap.put("cheng", "小橙");
        linkedHashMap.put("huang", "小黄");
        linkedHashMap.put("lv", "小绿");
        linkedHashMap.put("qing", "小青");
        linkedHashMap.put("lan", "小蓝");
        linkedHashMap.put("zi", "小紫");
        linkedHashMap.put("jishi", "鸡屎黄");
        linkedHashMap.put("yashi", "鸭屎绿");
        // 输出结果
        System.out.println(linkedHashMap);
        // 2. `V get(Object key)`:通过指定key获取value值
        System.out.println("======================get======================");
        String lv = linkedHashMap.get("lv");
        System.out.println(lv);
        lv = linkedHashMap.get("lv1");
        System.out.println(lv);
        // 3. `default V getOrDefault(Object key, V defaultValue)`:通过key获取value值,如果此key不存在则使用默认值输出
        System.out.println("======================getOrDefault======================");
        lv = linkedHashMap.getOrDefault("lv", "暂无数据");
        System.out.println(lv);
        lv = linkedHashMap.getOrDefault("lv1", "暂无数据");
        System.out.println(lv);
        // 4. `V remove(Object key)`:通过指定key移除key和value
        System.out.println("======================remove======================");
        String jishi = linkedHashMap.remove("jishi");
        System.out.println(jishi);
        jishi = linkedHashMap.remove("jishi");
        System.out.println(jishi);
        System.out.println(linkedHashMap);
        // 5. `boolean containsKey(Object key)`:判断Map集合中是否包含指定key
        System.out.println("======================containsKey======================");
        boolean cheng = linkedHashMap.containsKey("cheng");
        System.out.println(cheng);
        cheng = linkedHashMap.containsKey("cheng1");
        System.out.println(cheng);
        // 6. `boolean containsValue(Object value)`:判断集合中是否包含指定value
        System.out.println("======================containsValue======================");
        cheng = linkedHashMap.containsValue("鸭屎绿");
        System.out.println(cheng);
        cheng = linkedHashMap.containsValue("cheng1");
        System.out.println(cheng);
        // 7. `Collection<V> values()`:返回Map集合中的所有value值
        System.out.println("======================values======================");
        Collection<String> values = linkedHashMap.values();
        System.out.println(values);
        // 8. `Set<K> keySet()`:返回Map集合中的所有key值
        System.out.println("======================keySet======================");
        Set<String> keySet = linkedHashMap.keySet();
        System.out.println(keySet);
        // 9. `Set<Map.Entry<K, V>> entrySet()`:返回Map集合中的所有key-value值(返回所有键值对)
        // 1. 返回值为Set集合,Set集合中有一个Entry接口,其中包含了获取Key和Value的方法
        // 1. `K getKey()`:获取Entry中的key值
        // 2. `V getValue()`:获取Entry中的value值
        System.out.println("======================Entry======================");
        Set<Map.Entry<String, String>> entries = linkedHashMap.entrySet();
        System.out.println(entries);
        // 10. `int size()`:返回Map集合中的key-value数量
        System.out.println("======================size======================");
        int size = linkedHashMap.size();
        System.out.println(size);
        // 11. `void clear()`:清空Map集合所有元素
        System.out.println("======================clear======================");
        System.out.println(size);
        linkedHashMap.clear();
        System.out.println(linkedHashMap.size());
        // 12. `boolean isEmpty()`:判断Map集合是否为空
        System.out.println("======================isEmpty======================");
        boolean empty = linkedHashMap.isEmpty();
        System.out.println(empty);
        // 添加数据
        linkedHashMap.put("pink", "粉");
        System.out.println(linkedHashMap);
        empty = linkedHashMap.isEmpty();
        System.out.println(empty);
    }
}
6. Map接口之HashTable实现类(熟悉)
1. HashTable类概述

HashTable与HashMap几乎相同,包括底层数据结构,唯一的区别在于HashMap是线程不安全的,HashTable是线程安全,除此之外所有的使用都相同 HashTable是线程安全的,其方法使用的有synchronized关键字修饰

2. HashTable构造方法
// 空参构造方法用于创建Hashtable对象
public Hashtable() {
    // 默认容量大小为11
    this(11, 0.75f);
}
// 指定自定义容量大小创建Hashtable对象
public Hashtable(int initialCapacity) {
    this(initialCapacity, 0.75f);
}
// 指定Map集合创建Hashtable对象
public Hashtable(Map<? extends K, ? extends V> t) {
    this(Math.max(2*t.size(), 11), 0.75f);
    putAll(t);
}
3. HashTable常用方法
  1. V put(K key, V value):向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)

  2. V get(Object key):通过指定key获取value值

  3. default V getOrDefault(Object key, V defaultValue):通过key获取value值,如果此key不存在则使用默认值输出

  4. V remove(Object key):通过指定key移除key和value

  5. boolean containsKey(Object key):判断Map集合中是否包含指定key

  6. boolean containsValue(Object value):判断集合中是否包含指定value

  7. Collection<V> values():返回Map集合中的所有value值

  8. Set<K> keySet():返回Map集合中的所有key值

  9. Set<Map.Entry<K, V>> entrySet():返回Map集合中的所有key-value值(返回所有键值对)

    1. 返回值为Set集合,Set集合中有一个Entry接口,其中包含了获取Key和Value的方法

      1. K getKey():获取Entry中的key值

      2. V getValue():获取Entry中的value值

  10. int size():返回Map集合中的key-value数量

  11. void clear():清空Map集合所有元素

  12. boolean isEmpty():判断Map集合是否为空

  13. public synchronized Enumeration<V> elements():返回此集合数据

  14. public synchronized Enumeration<K> keys():返回此集合的key

4. HashTable代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建Hashtable对象
        Hashtable<String, String> hashtable = new Hashtable<>();
        // 1. `V put(K key, V value)`:向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)
        System.out.println("======================put======================");
        hashtable.put("chi", "小赤");
        hashtable.put("cheng", "小橙");
        hashtable.put("huang", "小黄");
        hashtable.put("lv", "小绿");
        hashtable.put("qing", "小青");
        hashtable.put("lan", "小蓝");
        hashtable.put("zi", "小紫");
        hashtable.put("jishi", "鸡屎黄");
        hashtable.put("yashi", "鸭屎绿");
        // 输出结果
        System.out.println(hashtable);
        // 2. `V get(Object key)`:通过指定key获取value值
        System.out.println("======================get======================");
        String lv = hashtable.get("lv");
        System.out.println(lv);
        lv = hashtable.get("lv1");
        System.out.println(lv);
        // 3. `default V getOrDefault(Object key, V defaultValue)`:通过key获取value值,如果此key不存在则使用默认值输出
        System.out.println("======================getOrDefault======================");
        lv = hashtable.getOrDefault("lv", "暂无数据");
        System.out.println(lv);
        lv = hashtable.getOrDefault("lv1", "暂无数据");
        System.out.println(lv);
        // 4. `V remove(Object key)`:通过指定key移除key和value
        System.out.println("======================remove======================");
        String jishi = hashtable.remove("jishi");
        System.out.println(jishi);
        jishi = hashtable.remove("jishi");
        System.out.println(jishi);
        System.out.println(hashtable);
        // 5. `boolean containsKey(Object key)`:判断Map集合中是否包含指定key
        System.out.println("======================containsKey======================");
        boolean cheng = hashtable.containsKey("cheng");
        System.out.println(cheng);
        cheng = hashtable.containsKey("cheng1");
        System.out.println(cheng);
        // 6. `boolean containsValue(Object value)`:判断集合中是否包含指定value
        System.out.println("======================containsValue======================");
        cheng = hashtable.containsValue("鸭屎绿");
        System.out.println(cheng);
        cheng = hashtable.containsValue("cheng1");
        System.out.println(cheng);
        // 7. `Collection<V> values()`:返回Map集合中的所有value值
        System.out.println("======================values======================");
        Collection<String> values = hashtable.values();
        System.out.println(values);
        // 8. `Set<K> keySet()`:返回Map集合中的所有key值
        System.out.println("======================keySet======================");
        Set<String> keySet = hashtable.keySet();
        System.out.println(keySet);
        // 9. `Set<Map.Entry<K, V>> entrySet()`:返回Map集合中的所有key-value值(返回所有键值对)
        // 1. 返回值为Set集合,Set集合中有一个Entry接口,其中包含了获取Key和Value的方法
        // 1. `K getKey()`:获取Entry中的key值
        // 2. `V getValue()`:获取Entry中的value值
        System.out.println("======================Entry======================");
        Set<Map.Entry<String, String>> entries = hashtable.entrySet();
        System.out.println(entries);
        // 10. `int size()`:返回Map集合中的key-value数量
        System.out.println("======================size======================");
        int size = hashtable.size();
        System.out.println(size);
        // 11. `void clear()`:清空Map集合所有元素
        System.out.println("======================clear======================");
        System.out.println(size);
        hashtable.clear();
        System.out.println(hashtable.size());
        // 12. `boolean isEmpty()`:判断Map集合是否为空
        System.out.println("======================isEmpty======================");
        boolean empty = hashtable.isEmpty();
        System.out.println(empty);
        // 添加数据
        hashtable.put("pink", "粉");
        hashtable.put("chi", "小赤");
        hashtable.put("cheng", "小橙");
        hashtable.put("huang", "小黄");
        hashtable.put("lv", "小绿");
        hashtable.put("qing", "小青");
        hashtable.put("lan", "小蓝");
        hashtable.put("zi", "小紫");
        hashtable.put("jishi", "鸡屎黄");
        hashtable.put("yashi", "鸭屎绿");
        System.out.println(hashtable);
        empty = hashtable.isEmpty();
        System.out.println(empty);
        System.out.println("=================================");
        // 13. `public synchronized Enumeration<V> elements()`:返回此集合数据
        System.out.println("=================================");
        Enumeration<String> elements = hashtable.elements();
        System.out.println(elements);
        while (elements.hasMoreElements()) {
            String nextElement = elements.nextElement();
            System.out.println(nextElement);
        }
        // 14. `public synchronized Enumeration<K> keys()`:返回此集合的key
        System.out.println("=================================");
        Enumeration<String> keys = hashtable.keys();
        System.out.println(keys);
        while (keys.hasMoreElements()) {
            String nextElement = keys.nextElement();
            System.out.println(nextElement);
        }
    }
}
7. Map接口之TreeMap实现类(了解熟悉)
1. TreeMap概述

TreeMap是Map的一个子孙类,他是一个有序的Key-Value集合,并且底层是使用于红黑树实现,TreeMap底层是直接使用红黑树,定义为Entry root,这也是TreeMap的核心代码 private transient Entry<K,V> root;这段定义就是TreeMap的底层

// 红黑树的底层实现
static final class Entry<K,V> implements Map.Entry<K,V> {
    // Key值
    K key;
    // value值
    V value;
    // 左子树
    Entry<K,V> left;
    // 右子树
    Entry<K,V> right;
    // 父级
    Entry<K,V> parent;
    // 代表红黑树-->默认是Black(黑树)
    boolean color = BLACK;


    Entry(K key, V value, Entry<K,V> parent) {
        this.key = key;
        this.value = value;
        this.parent = parent;
    }
}
2. TreeMap构造方法
// 空参构造方法用于创建TreeMap对象
public TreeMap() {
    comparator = null;
}
// 指定Map集合当做参数创建TreeMap对象
public TreeMap(Map<? extends K, ? extends V> m) {
    comparator = null;
    putAll(m);
}
// 指定比较器创建TreeMap对象
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}
3. TreeMap常用方法-->Map集合中有的方法全都可以使用
  1. public V put(K key, V value):向集合中添加key-value元素

  2. public V get(Object key):通过指定key获取value值

  3. public Set<K> keySet():获取集合中的所有key值

  4. public Collection<V> values():获取集合中的所有value值

  5. public int size():获取集合中元素数量

  6. public void clear():清空集合中的元素

  7. public boolean isEmpty():判断集合是否为空

4. TreeMap代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建TreeMap集合对象
        TreeMap<String, String> treeMap = new TreeMap<>();
        // 1. `public V put(K key, V value)`:向集合中添加key-value元素
        System.out.println("=======================put=======================");
        treeMap.put("name", "基尼太美");
        treeMap.put("age", "35");
        treeMap.put("sex", "未知");
        treeMap.put("sex", "妖");
        treeMap.put("hobby", "唱,跳,rap,篮球");
        System.out.println(treeMap);
        // 2. `public V get(Object key)`:通过指定key获取value值
        System.out.println("=======================get=======================");
        String hobby = treeMap.get("hobby");
        System.out.println(hobby);
        // 3. `public Set<K> keySet()`:获取集合中的所有key值
        System.out.println("=======================keySet=======================");
        Set<String> keySet = treeMap.keySet();
        System.out.println(keySet);
        // 4. `public Collection<V> values()`:获取集合中的所有value值
        System.out.println("=======================values=======================");
        Collection<String> values = treeMap.values();
        System.out.println(values);
        // 5. `public int size()`:获取集合中元素数量
        System.out.println("=======================size=======================");
        int size = treeMap.size();
        System.out.println(size);
        // 6. `public void clear()`:清空集合中的元素
        System.out.println("=======================clear=======================");
        treeMap.clear();
        // 7. `public boolean isEmpty()`:判断集合是否为空
        System.out.println("=======================isEmpty=======================");
        boolean empty = treeMap.isEmpty();
        System.out.println(empty);
    }
}
6. TreeMap比较器构造方法(了解熟悉)

使用TreeMap构造方法的比较器,在创建对象时使用外部比较器(匿名内部类),按照升序或降序比较 如果是Java内部的类则不需要使用内部比较器,如果是非内部类则需要实现内部比较器-->实现Comparable接口

  1. 比较器代码

public class Demo {
    public static void main(String[] args) {
        // 使用TreeMap集合传入对象
        // TreeMap通过Key排序,如果使用Java提供类则一般会实现比较器,此时则默认正序
        // 如果想要实现逆序则需要使用TreeMap集合中的自定义比较器
        TreeMap<String, Student> treeMap = new TreeMap<>();
        // 定义Student对象
        treeMap.put("5", new Student("小明", 18));
        treeMap.put("7", new Student("小白", 17));
        treeMap.put("1", new Student("小蓝", 19));
        treeMap.put("6", new Student("小红", 18));
        treeMap.put("3", new Student("小黄", 16));
        treeMap.put("2", new Student("小绿", 18));
        treeMap.put("4", new Student("小青", 17));
        // 输出结果
        System.out.println(treeMap);
        // 使用自定义比较器
        TreeMap<String, Student> treeMap1 = new TreeMap<>(new Comparator<String>() {
            /**
             * 实现外部比较器的方法
             * @param o1 对象1
             * @param o2 对象2
             * @return 返回结果如果是负数则小, 0则相同, 正数则大
             */
            @Override
            public int compare(String o1, String o2) {
                // 对比两个String值的大小
                // 如果o2调用者小于o1则向后排序,如果大则向前排序
                return o2.compareTo(o1);
            }
        });
        // 定义Student对象
        treeMap1.put("5", new Student("小明", 18));
        treeMap1.put("7", new Student("小白", 17));
        treeMap1.put("1", new Student("小蓝", 19));
        treeMap1.put("6", new Student("小红", 18));
        treeMap1.put("3", new Student("小黄", 16));
        treeMap1.put("2", new Student("小绿", 18));
        treeMap1.put("4", new Student("小青", 17));
        // 输出结果
        System.out.println(treeMap1);

        // 使用实体类当做key值
        TreeMap<Student, String> treeMap2 = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o2.getAge() - o1.getAge();
            }
        });
        // 添加数据
        treeMap2.put(new Student("小明", 16), "");
        treeMap2.put(new Student("小明", 12), "");
        treeMap2.put(new Student("小明", 11), "");
        treeMap2.put(new Student("小明", 13), "");
        treeMap2.put(new Student("小明", 15), "");
        treeMap2.put(new Student("小明", 14), "");
        System.out.println(treeMap2);

        TreeMap<Student, String> treeMap3 = new TreeMap<>();
        // 添加数据
        treeMap3.put(new Student("小明", 16), "");
        treeMap3.put(new Student("小明", 12), "");
        treeMap3.put(new Student("小明", 11), "");
        treeMap3.put(new Student("小明", 13), "");
        treeMap3.put(new Student("小明", 15), "");
        treeMap3.put(new Student("小明", 14), "");
        System.out.println(treeMap3);
    }
}
4. Map集合总结以及常用实现类(掌握)
1. Map接口实现类区别

Map集合普遍都是Key-Value集合形式,并且所有的Key都不允许重复 HashMap底层是由哈希表实现,JDK1.8后如果存储数据超过8个则改为红黑树 LinkedHashMap底层是由哈希表+链表实现,不论数据长短都是相同,有序集合 HashTable底层与HashMap相同,但是是线程安全的 TreeMap底层是红黑树实现

2. Map接口常用方法
  1. V put(K key, V value):向Map集合中添加元素(键值对元素),如果添加的可以是重复的则会覆盖value值(key不覆盖)

  2. V get(Object key):通过指定key获取value值

  3. V remove(Object key):通过指定key移除key和value

  4. boolean containsKey(Object key):判断Map集合中是否包含指定key

  5. boolean containsValue(Object value):判断集合中是否包含指定value

  6. Set<Map.Entry<K, V>> entrySet():返回Map集合中的所有key-value值(返回所有键值对)

  7. int size():返回Map集合中的key-value数量

  8. boolean isEmpty():判断Map集合是否为空

3. Map集合的创建方式以及常用实现类

Map集合创建方式常用多态方式创建,所以使用时只能使用Map接口定义的方法,如果后期会使用到实现类的某些方法则单独创建 Map接口的常用实现类是HashMap类,后期使用他最多

4. Map集合常用方法使用以及多态方式创建对象
public class Demo {
    public static void main(String[] args) {
        // 多态方式创建Map集合对象
        Map<String, List<String>> map = new HashMap<>();
        // 定义List集合
        List<String> list1 = new ArrayList<>();
        // 向List集合中添加数据
        list1.add("锄禾日当午");
        list1.add("汗滴禾下土");
        list1.add("谁知盘中餐");
        list1.add("粒粒皆辛苦");
        List<String> list2 = new ArrayList<>();
        // 向List集合中添加数据
        list2.add("床前明月光");
        list2.add("疑是地上霜");
        list2.add("举头望明月");
        list2.add("低头思故乡");
        List<String> list3 = new ArrayList<>();
        // 向List集合中添加数据
        list3.add("君问归期未有期");
        list3.add("巴山夜雨涨秋池");
        list3.add("何当共剪西窗烛");
        list3.add("却话巴山夜雨时");
        // 将古诗添加到Map集合中
        map.put("悯农", list1);
        map.put("静夜思", list2);
        map.put("夜雨寄北", list3);
        System.out.println(map);
        // 通过key查询map集合,如果存在则输出结果如果不存在则输出不存在
        // 第一种方式使用查询key判断
        // map.containsKey()
        String name = "悯农1";
        if (map.containsKey(name)) {
            System.out.println(map.get(name));
        } else {
            System.out.println("古诗<" + name + ">不存在!");
        }
        // list集合添加Map集合数据
        Map<String, String> map1 = new HashMap<>();
        map1.put("name", "基尼太美");
        map1.put("age", "35");
        map1.put("sex", "未知");
        map1.put("sex", "妖");
        map1.put("hobby", "唱,跳,rap,篮球");
        Map<String, String> map2 = new HashMap<>();
        map2.put("name", "基尼太美");
        map2.put("age", "35");
        map2.put("sex", "未知");
        map2.put("sex", "妖");
        map2.put("hobby", "唱,跳,rap,篮球");
        Map<String, String> map3 = new HashMap<>();
        map3.put("name", "基尼太美");
        map3.put("age", "35");
        map3.put("sex", "未知");
        map3.put("sex", "妖");
        map3.put("hobby", "唱,跳,rap,篮球");
        // 定义List集合
        List<Map<String, String>> list = new ArrayList<>();
        // 向集合中添加数据
        list.add(map1);
        list.add(map2);
        list.add(map3);
        System.out.println(list);
        // 对于以上两种集合遍历
        // 遍历Map集合
        Set<String> keySet = map.keySet();
        // 遍历KeySet集合
        for (String key : keySet) {
            // 打印key值
            System.out.println(key);
            // 通过key获取value值
            List<String> tempList = map.get(key);
            // 遍历value数据
            for (String values : tempList) {
                System.out.println("----" + values);
            }
        }
        // List集合遍历
        for (Map<String, String> objectMap : list) {
            // 遍历map集合
            Set<String> keySet1 = objectMap.keySet();
            for (String key : keySet1) {
                String value = objectMap.get(key);
                System.out.println(key + "----" + value);
            }
        }
    }
}

6 . Set接口(掌握)

1. Set概述

Set接口继承自Collection接口,在Set接口中所有方法基本与Collection相同,除此之外,没有任何相同内容,具体实现也不是自己写的 Set集合是一个无序(无序是指插入顺序与取出顺序不一致),且不可重复集合,Set集合中的元素与HashMap的key的值相同属性 Set集合分为三个实现类1. HashSet,2. LinkedHashSet,3. TreeSet

2. Set常用方法
3. Set接口之HashSet实现类(熟悉/掌握)
1. HashSet概述

HashSet是Set接口的直接子类,但又不完全依赖于Set接口,原因是其内部实现是使用HashMap集合的方式(Set集合与Map集合的关系就是继父,继子关系) HashSet集合的具体实现是由HashMap集合的方法组成-->private transient HashMap<E,Object> map;HashSet集合中创建的Map对象

2. HashSet构造方法
// 创建HashSet集合对象
public HashSet() {
    // 在创建HashSet对象时一并创建HashMap对象
    map = new HashMap<>();
}
// 指定初始化容量创建HashSet对象
public HashSet(int initialCapacity) {
    map = new HashMap<>(initialCapacity);
}
// 指定Collection集合创建HashSet对象
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}
3. HashSet常用方法
  1. public boolean add(E e):向集合中添加元素

  2. public boolean contains(Object o):判断是否存在某个元素

  3. public boolean remove(Object o):从集合中移除指定元素

  4. public int size():返回集合元素数量(集合长度)

  5. public boolean isEmpty():判断集合是否为空

  6. public void clear():清空集合中的所有元素

  7. public Iterator<E> iterator():返回Set集合的迭代器对象

4. HashSet代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建HashSet集合对象
        HashSet<String> set = new HashSet<>();
        // 1. `public boolean add(E e)`:向集合中添加元素
        set.add("菜虚鲲");
        set.add("刘亦菲");
        set.add("鞠婧祎");
        set.add("古天乐");
        set.add("梅超风");
        set.add("裘千尺");
        System.out.println(set);
        // 2. `public boolean contains(Object o)`:判断是否存在某个元素
        System.out.println("===============================");
        boolean isContains = set.contains("菜虚鲲");
        System.out.println(isContains);
        isContains = set.contains("菜虚鲲1");
        System.out.println(isContains);
        // 3. `public boolean remove(Object o)`:从集合中移除指定元素
        System.out.println("===============================");
        boolean isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        // 4. `public int size()`:返回集合元素数量(集合长度)
        System.out.println("===============================");
        System.out.println(set);
        int size = set.size();
        System.out.println(size);
        // 5. `public boolean isEmpty()`:判断集合是否为空
        System.out.println("===============================");
        boolean empty = set.isEmpty();
        System.out.println(empty);
        // 7. `public Iterator<E> iterator()`:返回Set集合的迭代器对象
        System.out.println("===============================");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            // 输出结果
            String next = iterator.next();
            System.out.println(next);
        }
        // 6. `public void clear()`:清空集合中的所有元素
        System.out.println("===============================");
        set.clear();
        System.out.println(set);
        System.out.println(set.size());
        System.out.println(set.isEmpty());
    }
}
4. Set接口之LinkedHashSet实现类(了解)
1. LinkedHashSet概述

LinkedHashSet是Set接口的实现类,方法与Set接口大致相同,与HashSet用法也大致相同,唯一的却别在于LinkedHashSet是有序集合,同样底层通过Map集合实现 此时LinkedHashSet已经开始不背人,直接继承HashSet,区别在于调用的是HashSet中的创建LinkedHashMap的构造方法 调用的构造方法如下

// HashSet的构造方法
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    // 创建对象时改为LinkedHashMap对象
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
2. LinkedHashSet构造方法
// 创建LinkedHashSet对象
public LinkedHashSet() {
    super(16, .75f, true);
}
// 创建LinkedHashSet对象并是这初始化容量
public LinkedHashSet(int initialCapacity) {
    super(initialCapacity, .75f, true);
}
// 创建LinkedHashSet对象并添加指定集合数据
public LinkedHashSet(Collection<? extends E> c) {
    super(Math.max(2*c.size(), 11), .75f, true);
    addAll(c);
}
3. LinkedHashSet常用方法
  1. public boolean add(E e):向集合中添加元素

  2. public boolean contains(Object o):判断是否存在某个元素

  3. public boolean remove(Object o):从集合中移除指定元素

  4. public int size():返回集合元素数量(集合长度)

  5. public boolean isEmpty():判断集合是否为空

  6. public void clear():清空集合中的所有元素

  7. public Iterator<E> iterator():返回Set集合的迭代器对象

4. LinkedHashSet代码案例
public class Demo {
    public static void main(String[] args) {
        // 创建LinkedHashSet集合对象
        LinkedHashSet<String> set = new LinkedHashSet<>();
        // 1. `public boolean add(E e)`:向集合中添加元素
        set.add("菜虚鲲");
        set.add("刘亦菲");
        set.add("鞠婧祎");
        set.add("古天乐");
        set.add("梅超风");
        set.add("裘千尺");
        System.out.println(set);
        // 2. `public boolean contains(Object o)`:判断是否存在某个元素
        System.out.println("===============================");
        boolean isContains = set.contains("菜虚鲲");
        System.out.println(isContains);
        isContains = set.contains("菜虚鲲1");
        System.out.println(isContains);
        // 3. `public boolean remove(Object o)`:从集合中移除指定元素
        System.out.println("===============================");
        boolean isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        // 4. `public int size()`:返回集合元素数量(集合长度)
        System.out.println("===============================");
        System.out.println(set);
        int size = set.size();
        System.out.println(size);
        // 5. `public boolean isEmpty()`:判断集合是否为空
        System.out.println("===============================");
        boolean empty = set.isEmpty();
        System.out.println(empty);
        // 7. `public Iterator<E> iterator()`:返回Set集合的迭代器对象
        System.out.println("===============================");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            // 输出结果
            String next = iterator.next();
            System.out.println(next);
        }
        // 6. `public void clear()`:清空集合中的所有元素
        System.out.println("===============================");
        set.clear();
        System.out.println(set);
        System.out.println(set.size());
        System.out.println(set.isEmpty());
    }
}
5. Set接口之TreeSet实现类(了解)
1. TreeSet概述

TreeSet底层是由TreeMap实现,内部直接调用TreeMap方法,相当于一个小号的TreeMap集合,同样也是单列集合,同样通过Key存储数据 使用时同样是按照比较器添加数据,如果是自定义实体类想向TreeSet集合中添加数据必须实现Comparable接口,或者使用匿名内部类方式才可以,否则会出现异常 TreeSet底层实现

// 声明变量,用于创建TreeMap集合对象
private transient NavigableMap<E,Object> m;

// 构造方法用于给NavigableMap集合初始值
TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}
// 创建TreeSet集合对象
public TreeSet() {
    // 调用上面的构造方法,并创建TreeMap集合对象
    this(new TreeMap<E,Object>());
}
2. TreeSet构造方法
// 创建TreeSet集合对象
public TreeSet() {
    // 调用上面的构造方法,并创建TreeMap集合对象
    this(new TreeMap<E,Object>());
}
// 指定Collection集合参数创建TreeSet集合对象
public TreeSet(Collection<? extends E> c) {
    this();
    addAll(c);
}
// 指定比较器创建TreeSet集合对象
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
3. TreeSet常用方法
  1. public boolean add(E e):向集合中添加元素

  2. public boolean contains(Object o):判断是否存在某个元素

  3. public boolean remove(Object o):从集合中移除指定元素

  4. public int size():返回集合元素数量(集合长度)

  5. public boolean isEmpty():判断集合是否为空

  6. public void clear():清空集合中的所有元素

  7. public Iterator<E> iterator():返回Set集合的迭代器对象

4. TreeSet代码案例
public class Demo {
    public static void main(String[] args) {
        // 使用Java内部提供的类创建TreeMap集合对象
        TreeSet<String> set = new TreeSet<>();
        // 1. `public boolean add(E e)`:向集合中添加元素
        set.add("6");
        set.add("4");
        set.add("2");
        set.add("3");
        set.add("5");
        set.add("1");
        System.out.println(set);
        // 2. `public boolean contains(Object o)`:判断是否存在某个元素
        System.out.println("===============================");
        boolean isContains = set.contains("菜虚鲲");
        System.out.println(isContains);
        isContains = set.contains("菜虚鲲1");
        System.out.println(isContains);
        // 3. `public boolean remove(Object o)`:从集合中移除指定元素
        System.out.println("===============================");
        boolean isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        isRemove = set.remove("裘千尺");
        System.out.println(isRemove);
        // 4. `public int size()`:返回集合元素数量(集合长度)
        System.out.println("===============================");
        System.out.println(set);
        int size = set.size();
        System.out.println(size);
        // 5. `public boolean isEmpty()`:判断集合是否为空
        System.out.println("===============================");
        boolean empty = set.isEmpty();
        System.out.println(empty);
        // 7. `public Iterator<E> iterator()`:返回Set集合的迭代器对象
        System.out.println("===============================");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            // 输出结果
            String next = iterator.next();
            System.out.println(next);
        }
        // 6. `public void clear()`:清空集合中的所有元素
        System.out.println("===============================");
        set.clear();
        System.out.println(set);
        System.out.println(set.size());
        System.out.println(set.isEmpty());


        System.out.println("===============================");
        // 使用匿名内部类更改比较器顺序
        // 使用Java内部提供的类创建TreeMap集合对象
        TreeSet<String> set1 = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        // 1. `public boolean add(E e)`:向集合中添加元素
        set1.add("6");
        set1.add("4");
        set1.add("2");
        set1.add("3");
        set1.add("5");
        set1.add("1");
        System.out.println(set1);

        System.out.println("===============================");
        // 使用实体类添加set集合数据
        TreeSet<Student> set2 = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                // Student对象是没有比较方法的,所以直接调用其属性的比较方法即可
                // 如果是字符串调用compareTo方法
                // 如果是数字类型则直接减法运算即可
                // 使用年龄升序
                return o1.getAge() - o2.getAge();
            }
        });
        // 添加数据
        set2.add(new Student("裘千尺", 15));
        set2.add(new Student("梅超风", 11));
        set2.add(new Student("黑山老妖", 16));
        set2.add(new Student("肾虚公子", 14));
        set2.add(new Student("黑风怪", 12));
        set2.add(new Student("裘千仞", 17));
        set2.add(new Student("灭绝师太", 13));
        // 输出结果
        System.out.println(set2);

        System.out.println("===============================");
        // 使用内部比较器比较-->Student实现Comparable接口即可
        // 使用实体类添加set集合数据
        TreeSet<Student> set3 = new TreeSet<>();
        // 添加数据
        set3.add(new Student("裘千尺", 15));
        set3.add(new Student("梅超风", 11));
        set3.add(new Student("黑山老妖", 16));
        set3.add(new Student("肾虚公子", 14));
        set3.add(new Student("黑风怪", 12));
        set3.add(new Student("裘千仞", 17));
        set3.add(new Student("灭绝师太", 13));
        // 输出结果
        System.out.println(set3);
    }
}
6. Set接口实现类总结(掌握)
1. Set接口实现类区别

Set接口的实现类没有区别,都是使用的Map接口的实现类直接调用,实现Set的方法 Set接口的实现类统一无序(LinkedHashMap是有序的),且内容不能重复 底层实现对照Map接口实现类对应

2. Set接口常用方法
  1. public boolean add(E e):向集合中添加元素

  2. public boolean contains(Object o):判断是否存在某个元素

  3. public boolean remove(Object o):从集合中移除指定元素

  4. public int size():返回集合元素数量(集合长度)

  5. public boolean isEmpty():判断集合是否为空

  6. public void clear():清空集合中的所有元素

  7. public Iterator<E> iterator():返回Set集合的迭代器对象

3. Set接口实现类创建对象

Set接口实现类创建对象方式一般使用多态创建,所有方法使用的都是Set预先定义好的,所以会用即可 创建对象方式例如:Set<泛型类型> 变量名 = new 实现类<>();

3. Set接口代码案例以及Set接口存放自定义对象测试

添加自定义对象时是否会重复验证 向Set集合中添加实体类对象会出现数据重复的问题,原因是Set集合都是通过Map集合实现的,所以使用的add方法的实现是put方法,而Map集合的put方法在验证时是使用equalshashCode来验证是否是相同的元素,所以实体类对象就必须重写equalshashCode方法才能让元素不重复

public class Demo {
    public static void main(String[] args) {
        System.out.println("===============================");
        // 使用实体类添加set集合数据
        HashSet<Student> set = new HashSet<>();
        // 添加数据
        set.add(new Student("裘千尺", 15));
        set.add(new Student("梅超风", 11));
        set.add(new Student("黑山老妖", 16));
        set.add(new Student("肾虚公子", 14));
        set.add(new Student("黑风怪", 12));
        set.add(new Student("裘千仞", 17));
        set.add(new Student("灭绝师太", 13));
        // 添加重复数据
        set.add(new Student("裘千尺", 15));
        set.add(new Student("梅超风", 11));
        set.add(new Student("黑山老妖", 16));
        set.add(new Student("肾虚公子", 14));
        set.add(new Student("黑风怪", 12));
        set.add(new Student("裘千仞", 17));
        set.add(new Student("灭绝师太", 13));
        // 输出结果
        System.out.println(set.size());
        System.out.println(set);

        System.out.println("===============================");
        HashSet<String> set1 = new HashSet<>();
        set1.add(new String("abc"));
        set1.add(new String("abc"));
        set1.add(new String("abc"));
        set1.add(new String("deg"));
        set1.add(new String("saf"));
        set1.add(new String("gdfsd"));
        set1.add(new String("bdf"));
        set1.add(new String("deg"));
        set1.add(new String("saf"));
        set1.add(new String("gdfsd"));
        set1.add(new String("bdf"));
        System.out.println(set1.size());
        System.out.println(set1);
    }
}

7. 比较器(了解熟悉)

1. 比较器概述

比较器的作用是用于集合中的排序使用

2. 比较器使用方式

比较器使用方式分为两种,第一种是实现Comparable接口,第二种是使用匿名内部类创建Comparable

1. 实现Comparable接口是内部比较器

代码案例 实体类

/**
 * 实现Comparable接口,并且重写compareTo方法,完成比较器的比较方式
 */
public class Student implements Comparable<Student> {

    /**
     * @param student 传入参数
     * @return 返回整数类型,-1小于,0相同,1大于
     */
    public int compareTo(Student student) {
        // 使用this对象对比
        return student.getAge() - this.age;
    }

    private String name;
    private Integer age;

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

测试案例

public class Demo {
    public static void main(String[] args) {
        System.out.println("===============使用内部比较器===============");
        // 使用实体类添加set集合数据
        TreeSet<Student> set1 = new TreeSet<>();
        // 添加数据
        set1.add(new Student("裘千尺", 15));
        set1.add(new Student("梅超风", 11));
        set1.add(new Student("黑山老妖", 16));
        set1.add(new Student("肾虚公子", 14));
        set1.add(new Student("黑风怪", 12));
        set1.add(new Student("裘千仞", 17));
        set1.add(new Student("灭绝师太", 13));
        // 输出结果
        System.out.println(set1);
    }
}
2. 匿名内部类创建Comparator是外部比较器

代码案例 实体类

/**
 * Student实体类对象
 */
public class Student {

    private String name;
    private Integer age;

    public Student() {
    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

测试案例

public class Demo {
    public static void main(String[] args) {
        System.out.println("===============使用外部比较器===============");
        // 使用内部比较器比较-->Student实现Comparable接口即可
        // 使用实体类添加set集合数据
        TreeSet<Student> set2 = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                // 使用年龄倒序排序
                return o2.getAge() - o1.getAge();
            }
        });
        // 添加数据
        set2.add(new Student("裘千尺", 15));
        set2.add(new Student("梅超风", 11));
        set2.add(new Student("黑山老妖", 16));
        set2.add(new Student("肾虚公子", 14));
        set2.add(new Student("黑风怪", 12));
        set2.add(new Student("裘千仞", 17));
        set2.add(new Student("灭绝师太", 13));
        // 输出结果
        System.out.println(set2);
    }
}

8. Collections工具类(熟悉)

1. Collections概述

这个类只包含操作或返回集合的静态方法。它包含多态算法操作的集合,它返回一个按指定的集合支持的新的集合,和其他一些零碎的东西。 说人话就是定义了一系列的操作集合的工具方法

2. Collections常用静态方法
  1. public static <T> boolean addAll(Collection<? super T> c, T... elements):向指定集合中添加多条数据

  2. public static final <T> List<T> emptyList():返回一个空集合

  3. public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):返回集合中的数据大小

  4. public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll):返回集合中的数据大小

  5. public static <T extends Comparable<? super T>> void sort(List<T> list):排序集合

  6. public static <T> void sort(List<T> list, Comparator<? super T> c):自定义排序集合

  7. public static void shuffle(List<?> list):混乱排序集合

  8. public static void reverse(List<?> list):反转排序集合

3. Collections代码案例

max和min较为常用一点

public class Demo {
    public static void main(String[] args) {
        // 定义一个List集合
        List<Integer> list = new ArrayList<>();
        // 添加数据
        // list.add(4);
        // list.add(2);
        // list.add(5);
        // list.add(3);
        // list.add(1);
        // System.out.println(list);
        // 1. `public static <T> boolean addAll(Collection<? super T> c, T... elements)`:向指定集合中添加多条数据
        System.out.println("=====================addAll=====================");
        boolean isAddAll = Collections.addAll(list, 4, 2, 5, 3, 1, 9, 6, 8, 7, 10, 14, 12, 13, 11, 15);
        System.out.println(isAddAll);
        System.out.println(list);
        // 2. `public static final <T> List<T> emptyList()`:返回一个空集合
        System.out.println("=====================emptyList=====================");
        // 返回空集合
        List<Object> objects = Collections.emptyList();
        System.out.println(objects);
        // 使用时类似于asList方法,一旦返回就是定长集合,不能添加数据
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
        // integers.add(6);
        System.out.println(integers);
        // 3. `public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)`:返回集合中的数据大小
        System.out.println("=====================max=====================");
        int max = 0;
        for (Integer integer : list) {
            if (max < integer) {
                max = integer;
            }
        }
        System.out.println(max);
        // 返回最大值方法
        Integer max1 = Collections.max(list);
        System.out.println(max1);
        // 4. `public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)`:返回集合中的数据大小
        System.out.println("=====================min=====================");
        Integer min = Collections.min(list);
        System.out.println(min);
        // 5. `public static <T extends Comparable<? super T>> void sort(List<T> list)`:排序集合
        System.out.println("=====================sort=====================");
        Collections.sort(list);
        System.out.println(list);
        // 6. `public static <T> void sort(List<T> list, Comparator<? super T> c)`:自定义排序集合
        System.out.println("=====================sort=====================");
        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // 设置倒序
                return o2 - o1;
            }
        });
        System.out.println(list);
        // 7. `public static void shuffle(List<?> list)`:混乱排序集合
        System.out.println("=====================shuffle=====================");
        Collections.shuffle(list);
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        // 修改为正序
        Collections.sort(list);
        System.out.println(list);
        Collections.shuffle(list);
        System.out.println(list);
        // 8. `public static void reverse(List<?> list)`:反转排序集合
        System.out.println("=====================reverse=====================");
        Collections.reverse(list);
        System.out.println(list);
    }
}

9. 总结

List集合常用的是ArrayList Map集合常用的是HashMap Set集合常用的是HashSet 其他集合,仅做对比以及区别牢记,只要上面的三个用熟练了,其他的集合也是会用的 泛型在集合中的使用认真看,泛型的定义与使用当前阶段认真练

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值