# 集合体系

# 单列集合 collection

# 遍历

# 迭代器

  1. 迭代器在遍历集合的时候是不依赖索引的

  2. 迭代器需要掌握三个方法

    // 迭代器
            ArrayList<String> list = new ArrayList<>();
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            list.add("ddd");
    
            Iterator<String> it = list.iterator();
    
            while (it.hasNext()){
                String str = it.next();
                System.out.println(str);
            }
    
  3. 迭代器的四个细节

    • 如果当前位置没有元素,继续获取会报错 NoSuchElementException
    • 迭代器遍历完成之后,指针不会复位,如果需要重新遍历,需要再次创建新的迭代器对象
    • 循环中只能使用一次next方法,否则会遍历到没有元素的位置,报错***NoSuchElementException***
    • 迭代器遍历时,不能使用集合的方法进行增加或者删除,只能使用迭代器自带的remove——方法删除

# 增强for

不能进行删除

// 增强for遍历,本质上还是迭代器(iterator)
        for (String str : list){
            System.out.println(str);
        }

# lambda表达式

不能进行删除

// forEach方法遍历每个元素,传递到s
list.forEach(s -> System.out.println(s));

# List


添加的元素是有序(存的顺序和取是顺序相同)、可重复、有索引

# List 特有方法

		// 添加元素,在指定位置插如元素,原来索引上的元素会依次向后移
        list.add(3,"fff");
        System.out.println(list);

        // 删除元素,删除指定位置的元素,返回被删除的元素
        System.out.println(list.remove(3));
        System.out.println(list);

        // 修改元素,将指定位置的元素更改为提供的元素,返回被修改的元素
        System.out.println(list.set(2, "CCC"));
        System.out.println(list);

        // 获取元素,获取指定位置的元素
        System.out.println(list.get(4));

# List 五种遍历方式

  1. 迭代器遍历

    遍历的过程中需要删除时使用

    // 1.迭代器遍历
            Iterator<String> it = list.iterator();
            while (it.hasNext()){
                String str = it.next();
                if (str.equals("bbb")){
                    it.remove(); // 删除元素
                }
                System.out.println(str);
            }
    
  2. 列表迭代器遍历

    遍历的过程中需要添加元素时使用

    // 2.列表迭代器遍历
            // 在遍历过程中可以添加元素
            ListIterator<String> listIt = list.listIterator();
            while (listIt.hasNext()){
                String str = listIt.next();
                if (str.equals("ccc")){
                    listIt.add("CCC"); // 添加元素
                }
                System.out.println(str);
            }
    
  3. 增强for遍历

    仅仅需要遍历时使用

    // 3.增强for
            for (String str: list){
                System.out.println(str);
            }
    
  4. Lambda表达式

    仅仅需要遍历时使用

    // 4.lambda表达式
            list.forEach( s -> System.out.println(s) );
    
  5. 普通for遍历

    如果遍历的时候需要操作索引时使用

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

# Set


# HashSet

添加的元素是无序、不重复、无索引

  • 底层原理

    • HashSet集合底层采取哈希表存储数据

    • 哈希表是一种对于增删改查数据性能都较好的结构

  • 哈希表组成

    • jdk8之前:数组+链表
    • jdk8开始:数组+链表+红黑树
  • 哈希值

    • 根据hashCode方法算出来的int类型的整数

    • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算

    • 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

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

		// 1.创建对象
        Student s1 = new Student("张三",20);
        Student s2 = new Student("张三",20);

        // 2.如果没有重写hashCode方法,计算出的hash值是不同的
        System.out.println(s1.hashCode());// 1523554304
        System.out.println(s2.hashCode());// 1175962212

		// 3.重写hashCode方法,计算的hash值就是相同的
		System.out.println(s1.hashCode());// 24022540
		System.out.println(s2.hashCode());// 24022540
  • 存入数据过程

    1. 创建一个默认长度16,默认 加载因 为0.75的数组

      当数组存入的数据达到(16*0.75=12)个时,数组就会扩容两倍

    2. 根据元素的哈希值跟数组的长度计算出应存入的位置

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

    4. 如果不为null,调用equals方法比较属序值

    5. 一样就不存入数据 不一样则存入数据,形成链表

      • jdk8之前:新元素存入数组,老元素挂在新元素下面

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

        当链表长度大于8且数组长度大于等于64时,当前链表就会转为红黑树

# LinkedHashSet

  • 有序、不重复、无索引

  • 这里的有序是指保证存储和取出的元素顺序一致

  • HashSet的子类,底层依然是哈希表,只是每个元素多了一个双链表的机制记录存储的顺序

# TreeSet

可排序、不重复、无索引

底层基于红黑树实现排序,增删改查性能都很好

  • 自定义排序规则的方式

    1. Javabean类实现Comparable接口,指定比较规则

      public class 类名 implements Comparable<TestStudent> {
          @Override
          // 返回值
          // 负数存在红黑树左边
          // 正数存在红黑树右边
          // 0表示已经存在,丢弃
          public int compareTo(类名 o) {
              return this.参数 - o.参数;
      }
      
    2. 创建集合时,自定义Compartor比较器对象,指定比较规则

      TreeSet<类名> ts = new TreeSet<>(new Comparator<类名>() {
      	@Override
          // 返回值与方式一同理		
          public int compare(类名 o1, 类名 o2) {
             	return o1.参数 - o2.参数;
          }
          });
      

    默认使用方式一,如果方式一不满足需求,使用方式二

    如果两种方式都存在,则使用的是第二种排序方式

# 使用场景

  • 如果想要集合中的元素可重复
    • 使用用ArrayList集合,基于数组(用的最多)
  • 如果想要集合中的元素可重复,而且当前的增删改查操作明显多于查询
    • 使用LinkedList集合,基于链表

  • 如果想对集合中的元素去重
    • 使用HashSet集合,基于哈希表(用的最多)
  • 如果相对集合中的元素去重并保证存取数据
    • 使用LinkedHashSet集合,基于哈希表的双链表,效率低于HashSet
  • 如果想对集合中的元素进行排序
    • 使用TreeSet集合,基于红黑树

# 双列集合 map

Map(映射)是一种常用的数据结构,它提供了一种键值对(Key-Value)的存储方式。Map接口是Java集合框架中的一员,它定义了一系列操作用于存储、检索、删除和操作键值对。

# HashMap

HashMap是基于哈希表实现的,它提供了快速的插入、删除和查找操作。键和值都可以为null,并且不保证元素的顺序。

# TreeMap

TreeMap基于红黑树(自平衡的二叉查找树)实现,它根据键的自然顺序或自定义比较器进行排序。TreeMap的元素按照键的有序状态进行存储。

# LinkedHashMap

LinkedHashMap是HashMap的一个子类,它保留了元素插入的顺序。在遍历时,元素按照插入顺序或最近访问顺序进行迭代。

# ConcurrentHashMap

ConcurrentHashMap是线程安全的HashMap实现,它支持高并发操作。它采用分段锁的方式来提供更好的并发性能。

Map接口提供了一系列常用的方法,包括:

  • 添加元素:put(key, value)
  • 获取元素:get(key)
  • 删除元素:remove(key)
  • 判断是否包含某个键:containsKey(key)
  • 判断是否包含某个值:containsValue(value)
  • 获取Map的大小:size()
  • 清空Map:clear()
  • 获取所有键的集合:keySet()
  • 获取所有值的集合:values()
  • 获取所有键值对的集合:entrySet()

# 遍历

  1. 使用Entry遍历:

    Map<String, Integer> map = new HashMap<>();
    // 添加键值对
    map.put("A", 1);
    map.put("B", 2);
    map.put("C", 3);
    
    for (Map.Entry<String, Integer> entry : map.entrySet()) {
        String key = entry.getKey();
        Integer value = entry.getValue();
        // 对键值对进行操作
        System.out.println("Key: " + key + ", Value: " + value);
    }
    
  2. 分别遍历键和值:

    Map<String, Integer> map = new HashMap<>();
    // 添加键值对
    map.put("A", 1);
    map.put("B", 2);
    map.put("C", 3);
    
    // 遍历键
    for (String key : map.keySet()) {
        // 对键进行操作
        System.out.println("Key: " + key);
    }
    
    // 遍历值
    for (Integer value : map.values()) {
        // 对值进行操作
        System.out.println("Value: " + value);
    }
    

# 使用场景

  • HashMap:

    • HashMap是最常用的Map实现类之一,适用于大多数情况。它提供了快速的插入、删除和查找操作。由于HashMap不保证元素的顺序,因此适用于不需要保持元素有序的场景。
  • LinkedHashMap:

    • LinkedHashMap是HashMap的子类,它保留了元素插入的顺序。在遍历时,元素按照插入顺序或最近访问顺序进行迭代。适用于需要保持元素插入顺序的场景。
  • TreeMap:

    • TreeMap基于红黑树实现,它根据键的自然顺序或自定义比较器进行排序。适用于需要按照键的有序状态进行存储和遍历的场景。
  • ConcurrentHashMap:

    • ConcurrentHashMap是线程安全的HashMap实现,它支持高并发操作。通过采用分段锁的方式来提供更好的并发性能。适用于多线程环境下需要高并发访问的场景。