1、集合概述

1.1 集合的体系结构

1.1.1 Collection:

  • List

    排列有序,可重复

    • ArrayList
      • 底层使用数组
      • 查询速度快,增删慢
      • 线程不安全
      • 容量不够时,容量的计算(扩容因子)
    • Vector
      • 底层使用数组实现
      • 查询速度快,增删慢
      • 线程安全,效率低
      • 容量不够时,Vector默认扩展一倍容量
    • LinkedList
      • 底层使用双向循环链表结构
      • 查询速度慢,增删快
      • 线程不安全
  • Set

    排列无序,不可重复

    • HashSet
      • 底层使用Hash表实现
      • 存取速度快
      • 内部是HashMap
    • TreeSet
      • 底部使用二叉树实现
      • 排序存储
      • 内部是TreeMap的SortedMap
    • LinkedHashSet
      • 采用Hash表存储,用双向链表记录插入顺序
      • 内部是LinkedHashMap
  • Queue

    • 在两端出入的List,可以用数组或链表实现

1.1.2 Map:

  • HashMap
    • 键不可重复,值可以重复
    • 底层是哈希表
    • 线程不安全
    • 允许Key为null,但是能有一个空Key,value也可以为null
  • ConcurrentHashMap
    • segment段
    • 线程安全的,继承了ReentrantLock
    • 并行度
    • java7与java8实现
  • HashTable
    • 键不可重复,值可以重复
    • 底层Hash表
    • 线程安全,但效率低
    • key,value都不允许为null
    • Properties
  • TreeMap
    • 键不可以重复,值可以重复
    • 底层是二叉树

image2021091211012894716314156940891.png

2、Collection

2.1 Collection概述

public interface Collection<E> extends Iterable<E> 
  • 集合与数组:

    • 都是容器,都可以存放多个数据
    • 数组的长度是不可变的,集合的长度是可变的
    • 数组可以存基本数据类型和引用数据类型,**集合只能存引用数据类型,**如果要存基本数据类型,需要存对应的包装类
  • 概述:

    • Collection是单例集合的顶层接口,继承了Iterable接口
  • Collection集合的常用方法:

    方法名 说明
    boolean add(E e) 添加元素
    boolean remove(Object o) 从集合中移除指定的元素
    void clear() 清空集合中的元素
    boolean contains(Object o) 判断集合中是否存在指定的元素
    boolean isEmpty() 判断集合是否为空
    int size() 集合的长度,也就是集合中元素的个数

2.2 迭代器

  • 因为Collection接口继承了Iterable接口,所以对于所有Collection的实现类,都要实现 iterator() 方法,此方法返回一个迭代器对象
  • 迭代器介绍
    • 迭代器,集合的专用遍历方式
    • Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到
  • Iterator常用方法:
    • boolean hasNext(): 判断当前位置是否有元素可以被取出
    • E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置
  • 遍历
    • while()
    • 增强for循环
  • 迭代器的删除操作
    • void remove(): 删除迭代器对象当前指向的元素

2.3 List接口

2.3.1 概述

  • List的特点:

    • 有序集合,这里的有序指的是存取顺序
    • 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
    • 与Set集合不同,列表通常允许重复的元素
  • List特有方法:

    void add(int index,E element) 在此集合中的指定位置插入指定的元素
    E remove(int index) 删除指定索引处的元素,返回被删除的元素
    E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
    E get(int index) 返回指定索引处的元素

2.3.2 ArrayList

  • 定义:

    public class ArrayList<E> 
    extends AbstractList<E> 
    implements List<E>, RandomAccess, Cloneable, Serializable
    
  • 特点:

    • 可以添加任意元素,可以加入重复元素,甚至可以加入多个null
    • 底层使用数组来实现存储
    • ArrayList基本等同于Vector,但是ArrayList是线程不安全的(因此效率更高),Vector是线程安全的
  • ArrayList扩容机制:

    • ArrayList底层维护了一个Object类型的数组elementData
    • 当使用无参构造创建ArrayList,数组初始长度为0,第一次添加,elemetData 扩容为10,如需再次扩容,则扩容1.5倍(扩容因子为1.5)
    • 当使用指定大小的构造器,则初始elementData长度为指定大小,如果需要扩容,则扩容1.5倍(扩容因子为1.5)
  • ArrayList底层源码:

2.3.3 Vector

  • 定义:

    public class Vector<E> 
    extends AbstractList<E> 
    implements List<E>, RandomAccess, Cloneable, Serializable
    
  • 概述:

    • Vector底层也是一个对象数组
    • Vector是线程同步的,即线程安全的,Vector类的操作方法带有synchronized

2.3.4 LinkedList

  • 定义

    public class LinkedList<E> 
    	extends AbstractSequentialList<E> 
    	implements List<E>, Deque<E>, Cloneable, Serializable
    
  • LinkedList底层实现了双向链表和双端队列特点

2.4 Set接口

2.4.1 概述

  • 特点:
    • 集合内元素无序,因此也没有索引
    • 不允许有重复元素,所以最多包含一个null
  • Set的遍历方式:
    • 迭代器遍历
    • 增强for循环遍历
  • 哈希值:
    • JDK根据对象地址或者字符串或数字计算出来的int类型的数值
    • Object类的public int hashCode() 返回对象的哈希码值
    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

2.4.2 HashSet

  • 定义:

    public class HashSet<E> 
        extends AbstractSet<E> 
        implements Set<E>, Cloneable, Serializable
    
  • HashSet集合特点:

    • 实现Set接口,底层数据结构是哈希表(HashMap+拉链法+红黑树)
    • 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
    • 没有带索引的方法,所以不能使用普通for循环遍历,但可以使用增强for遍历
    • 由于是Set集合,所以是不包含重复元素的集合
  • HashSet元素添加过程(保证元素唯一性源码):

    1. 根据对象的Hash值计算存储位置:

      ​ 当前位置没有元素就直接存入;

      ​ 当前位置有元素就进行第2步

    2. 当前元素的元素和已经存在的元素比较哈希值

      ​ 如果哈希值不同,则将当前元素进行存储

      ​ 如果哈希值相同,则进入第3步

    3. 通过equals()方法比较两个元素的内容

      ​ 如果内容不相同,则将当前元素进行存储

      ​ 如果内容相同,说明元素已经存在,则不存储当前元素

image20210913180058810.png

  • 添加位置:
    • 该对象的哈希值的相应位置(在哈希表中)没有元素,则直接添加到该位置
    • 已经存在一个元素,新建链表节点,挂在链表最后,
    • 该位置已经存在多个元素,元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小大于等于MINI_TREEIFY_CAPACITY,就会进行树化
  • 扩容机制:
    • HashSet底层是HashMap,第一次添加时,table数组扩容到16,临界值(threshold)是16*0.75(加载因子,loadFactor)=12
    • 如果table数组中的元素(不是HashSet中的元素个数,因为table中可能存在链表,树结构)达到临界值12,就会将table数组进行扩容,新的临界值就是32*0.75=24
    • 当一条链表中的元素达到一定个数TREEIFY_THRESHOLD(默认8个),并且table的大小大于等于MIN_TREEIFY_CAPACITY(默认为64),就会进行树化(红黑树)

2.4.3 TreeSet

  • 定义:

    public class TreeSet<E> 
        extends AbstractSet<E> 
        implements NavigableSet<E>, Cloneable, Serializable
    
  • 概述:

    • 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法

      • new Tree() 根据其元素的自然排序进行排序(可以在javabean内部实现Comparable接口,实现自然排序方法)

      • new Tree(Comparator comparator) 根据指定比较器进行排序

    • 没有索引,不能使用普通的for循环

    • 实现Set接口,不能包含重复元素

  • Comparable:

    • 在javabean实现Comparable接口,实现CompareTo方法:

          @Override
          public int compareTo(Student s) {
          // 返回 0
          // 返回 -1
          // 返回 1
              //按照年龄从小到大排序
             int num = this.age - s.age;
             int num2 = num==0?this.name.compareTo(s.name):num;
              return num2;
          }
      
  • Comparator接口:

    • 在定义TreeSet时,给定一个比较器

       TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
                  @Override
                  public int compare(Student s1, Student s2) {
                      //this.age - s.age
                      //s1,s2
                      int num = s1.getAge() - s2.getAge();
                      int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                      return num2;
                  }
              });
      

2.4.4 LinkedHashSet

  • 定义

    public class LinkedHashSet<E> 
        extends HashSet<E> 
        implements Set<E>, Cloneable, Serializable 
    
  • 概述:

    • LinkedHashSet是HashSet的子类
    • 底层是一个LinkedHashMap,底层维护一个 数组 + 双向链表
    • 根据元素的hashCode值来决定元素的存储位置,同时使用链表来维护元素的次序,使得元素看起来是以插入顺序保存的
    • 不允许添加重复元素

3、Map

3.1 Map概述

  • 定义:

    public interface Map<K, V> // K:键的类型;V:值的类型
    
  • Map集合的特点:

    • 键值对映射关系
    • 一个键对应一个值
    • 键不能重复,值可以重复
    • 元素存取无序
  • 基本方法:

    方法名 说明
    V put(K key,V value) 添加元素
    V remove(Object key) 根据键删除键值对元素
    void clear() 移除所有的键值对元素
    boolean containsKey(Object key) 判断集合是否包含指定的键
    boolean containsValue(Object value) 判断集合是否包含指定的值
    boolean isEmpty() 判断集合是否为空
    int size() 集合的长度,也就是集合中键值对的个数

3.2 Map集合的遍历

3.2.1 Map集合的获取功能

  • 方法介绍:

    方法名 说明
    V get(Object key) 根据键获取值
    Set<K> keySet() 获取所有键的集合
    Collection<V> values() 获取所有值的集合
    Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合

3.2.2 Map的遍历方式

遍历方式一:

  • 遍历思路:
    • 所有的元素都是以键值对的方式出现
    • 我们可以先获取所有的key的集合
    • 根据key值依次获取相应的value值
  • 具体实现:
    1. keySet() 获取所有键值集合
    2. 遍历集合,获取到每一个键,增强for实现
    3. 根据键值,用get(Object Key) 方法实现

遍历方式二:

  • 遍历思路:
    1. 直接获取所有键值对的集合,保存为一个Set集合
    2. 遍历键值对的集合
    3. 获取每一个键值对对应的key 和 value
  • 具体实现:
    1. Set<Map.Entry<K,V>> entrySet() 获取所有键值对集合
    2. 增强for 得到每一个Map.Entry
    3. 用getKey()得到键
    4. 用getValue()得到值

3.3 HashMap

  • 定义:

    public class HashMap<K,V> 
        extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable
    
  • 概述:

    • HashMap是以键值对的方式存储数据
    • Key不能重复,但是值可以重复,添加相同的Key,会覆盖原来的value,等同于修改
    • 与HashSet相同,不能保证映射顺序,因为底层是Hash表实现的
    • HashMap没有实现同步,因此是线程 不安全的
  • 扩容机制:

    1. HashMap底层维护了Node数组table,默认为null

    2. 当创建对象时,将加载因子(loadFactory)初始化为0.75

    3. 当添加键值对时,将key的哈希值在table中索引,然后判断索引处是否有元素

      • 如果没有元素直接添加
      • 如果有元素,继续判断该元素的key和准备加入的key是否相等
        1. 如果相等,则直接替换val
        2. 如果不相等,需要判断是树结构还是链表结构,做出相应的处理。

      如果发现容量不够,则需要扩容

    4. 第一次添加,则须扩容table到16,临界值(threshold)为12

    5. 以后再次扩容,则需要扩容到原来的2倍

    6. 在java8中,当一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

3.4 ConcurrentHashMap

  • 定义

    public class ConcurrentHashMap<K,V> 
        extends AbstractMap<K,V>
        implements ConcurrentMap<K,V>, Serializable
    
  • 概述:

    • 采用数组 + 链表/红黑树存储数据,当冲突链表达到一定长度时,链表会转换成红黑树
    • 使用 CAS + synchronized 保证线程安全

3.5 HashTable

  • 定义:

    public class Hashtable<K,V>
        extends Dictionary<K,V>
        implements Map<K,V>, Cloneable, java.io.Serializable
    
  • 概述:

    • 存放的元素是键值对
    • HashTable的键和值都不能为null,否则会抛出空指针异常
    • HashTable的使用方法基本上和HashMap一致
    • HashTable是线程安全的(方法粒度,在方法上加synchronized关键字),但是效率较低
  • 扩容机制:

    • 底层有数组 HashTable.Entry[] ,初始化大小为 11
    • 临界值 threshold 8 = 11*0.75

3.6 Properties

  • 定义:

    public class Properties 
        extends Hashtable<Object,Object>
    
  • 概述:

    • 继承HashTable类,也间接的实现了Map接口
    • 使用特点与HashTable相似,键值都不能为null
    • Properties可以从 .properties 文件中,加载数据到Properties对象,并进行读取和修改
    • 也是线程安全的

3.7 TreeMap

  • 定义:

    public class TreeMap<K,V>
        extends AbstractMap<K,V>
        implements NavigableMap<K,V>, Cloneable, java.io.Serializable
    
  • 概述:

    • 参照TreeSet,因为TreeSet的底层就是TreeMap实现的
    • 根据Key值进行排序,底部使用红黑树实现的