Java 集合类 笔记总结 + 作业

这篇博客总结了Java中的集合类,包括Collection、List、ArrayList、Vector、LinkedList、Queue、Deque、ArrayDeque、BlockingQueue、Map、HashMap、LinkedHashMap、Hashtable、TreeMap、Set、HashSet、LinkedHashSet和TreeSet等。详细介绍了HashMap的底层结构和特点,如数组+链表+红黑树,以及其加载因子、冲突避免策略等关键知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

集合类

1, 概述

  数据结构: 
       写代码
           
  集合类: 记忆/背会
           
Java中的集合类: 
    Java的集合类分为两个集合体系
        Collection集合体系: 存储单个数据
        Map集合体系: 存储key-value(键值对)数据

  key-value数据具有自我描述性 
            
                     
  先谈谁的子类谁的父类
  数据结构表现
  底层结构: 数组, 链表,  数组+链表
  如果是个数组: 数组的默认初始容器, 扩容机制
  有序, 重复, null
  线程安全

在这里插入图片描述

在这里插入图片描述

2, Collection

2.1 Collection的特点

  1, CollectionCollection集合体系的顶级接口
  2, Collection定义一个数据容器
  3, Collection的有些子实现存储元素有序,  有些子实现存储元素无序
  4, Collection有些子实现允许存储重复元素, 有些子实现不允许存储重复元素
  5, Collection有些子实现允许存储null, 有些子实现不允许存储null

2.2 Collection是api

          ----------------------添加删除相关-------------------------
         boolean add(E e): 添加操作
         boolean addAll(Collection<? extends E> c): 添加所有
         boolean contains(Object o): 查找某个元素是否存在
         boolean containsAll(Collection<?> c): 查找所有元素是否都存在
         boolean remove(Object o): 删除某个数据
         boolean removeAll(Collection<?> c): 删除所有匹配数据
         boolean retainAll(Collection<?> c): 保留所有匹配数据
      

          -----------------------------一些数据容器都具有辅助方法------------------------
         void clear()
         移除此 collection 中的所有元素(可选操作)。
         boolean equals(Object o)
         比较此 collection 与指定对象是否相等。
         int hashCode()
         返回此 collection 的哈希码值。
         boolean isEmpty()
         如果此 collection 不包含元素,则返回 trueint size()
         返回此 collection 中的元素数。       
     
          --------------------------------一些特殊的api-------------------------
         Object[] toArray()
         返回包含此 collection 中所有元素的数组。 
         <T> T[]  toArray(T[] a)
         返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。
//
         Iterator<E> iterator()
         返回在此 collection 的元素上进行迭代的迭代器。

toArray

   因为我们很多时候, 需要对集合类(数据容器 )进行数据遍历, 但是Collection没有办法直接遍历, 所以Collection定义了一个toArray方法, 把里面存储的数据放到数组中返回, 就可以实现数据遍历

第一个toArray()方法
         Object[] toArray()
         返回包含此 collection 中所有元素的数组。 

第二个toArray()方法 : 泛型方法
         <T> T[]  toArray(T[] a)
         返回包含此 collection 中所有元素的数组;
         返回数组的运行时类型与指定数组的运行时类型相同。

  ps1: 虽然这是个泛型方法(从泛型语法角度上传任何类型的数组都是可以的), 
  但是在实际运行的时候, 
  只有这个数组类型传对(和存储数据类型匹配), 才能正常运行  
    
  ps2: 在使用这个泛型方法的时候, 
  	如果数组足够长(假设 collection存储元素数量为n,
   数组长度至少是n), 返回的数据和传进去的参数, 实际上是一个数组 ;  
   如果我们给定参数数组长度不够长(空间不够容纳所有的collection元素),
   那么传进去的数组仅作为类型标记, 和返回的数组并不是同一个数组
    
  ps3: 在使用这个泛型方法的时候, 如果数组过长(collection存储元素数量为n, 
  数组长度大于n), 它会它数组的第n+1个位置置为null, n+1之后的位置不再处理

iterator

   		Collection<String> collection = new ArrayList<>();
        collection.add("zs");
        collection.add("ls");
        collection.add("wu");
        collection.add("zl");

        Iterator<String> iterator = collection.iterator();

        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
  Iterator类型:
boolean hasNext(): 向后是否可以遍历       
E next() : 向后遍历
void remove() : 删除刚刚遍历过的元素: (不要在未遍历之前删除, 也不要做连续的删除)
注意1: iterator本质
    Collection提供了一个toArray方法, 把数据转存到数组中, 然后遍历, 但是效率不高
    所以设计了iterator(原地遍历: 不复制数据, 仅维护标记)
    通过Collection的iterator方法产生了一个iterator对象, 这个对象的在内存上的本质就是iterator对象内维护了一些指向源collection对象数据的标记;   

注意2: 那么我们通过iterator对象来做遍历(遍历或者删除), 实际上是直接遍历(遍历或者删除)原collection对象中的数据

注意3: Iterator类型和它的方法
   hasNext(): 向后还有没有元素可以遍历
   next(): 向后遍历
   remove(): 删除刚刚遍历过的元素; 
    
注意4: 也就意味着不能在未遍历之前删除, 也不能做连续的删除
因为Iterator产生的iterator对象并不持有数据, iterator操作的都是源数据(iterator本身只是维护了一个指向源数据的标记)
    
注意5: remove不能在未遍历之前删除, 不能连续的删除:  也就意味着删除使用范围很狭窄, iterator主要是用来做遍历的(关注:hasNext, next )

在这里插入图片描述

并发修改异常

并发修改异常来源
  一些Collection的子实现是线程不安全的(加锁会导致运行效率降低), 在使用Iterator遍历的时候, 就会产生线程安全问题, 但是又不希望通过锁来保证线程安全(加锁会导致运行效率降低) ; 
  所以一些集合类就维护了一个标记(标记修改次数的标记), 当源集合数据发生修改, 标记会增加;
  在iterator对象中为了保证在遍历过程中源集合类数据没有被修改, 会在每次遍历之前检测自己保存的修改次数记录和源集合类是否一样, 如果不一样, 就认为源集合数据被别的线程修改, 抛出并发修改异常. 
  这是为了多线程遍历数据设计
  但是可能导致单线程情况下, 在遍历的过程中如果直接使用源集合类的修改结构的方法, 直接修改源集合数据, 也会抛出并发修改异常  
    
怎么避免在单线程情况下产生并发修改异常:  
  在遍历之前直接修改源集合数据, 或者在遍历完成之后修改, 不要在遍历中间过程修改

在这里插入图片描述

foreach

  我们Java中 foreach/增强for/加强for循环,  是依赖于iterator迭代 
  也就意味着, 要使用增强的for循环遍历数据, 就要有iterator方法
  同时也意味着, 如果我们使用foreach循环遍历某个Java容器, 不应该在遍历的过程中, 调用源集合类修改结构的方法直接修改源集合数据(会爆出并发修改异常)

  数组可以使用增强的for循环, 和iterator方法没有任何关系 (jvm对数组处理比较特殊), 是编译成普通的fori循环

在这里插入图片描述

3, List

3.1 List的特点

  1, ListCollection接口的子接口
  2, List定义数据结构为线性表
  3, List存储元素有序
  4, List允许存储重复数据
  5, List允许存储null

3.2 List 的 api

  -------------------List拥有从Collection继承的api---------------

  ----------------------添加删除相关-------------------------
         boolean add(E e): 添加操作
         boolean addAll(Collection<? extends E> c): 添加所有
         boolean contains(Object o): 查找某个元素是否存在
         boolean containsAll(Collection<?> c): 查找所有元素是否都存在
         boolean remove(Object o): 删除某个数据
         boolean removeAll(Collection<?> c): 删除所有匹配数据
         boolean retainAll(Collection<?> c): 保留所有匹配数据
      
          -----------------------------一些数据容器都具有辅助方法------------------------
         void clear()
         移除此 collection 中的所有元素(可选操作)。
         boolean equals(Object o)
         比较此 collection 与指定对象是否相等。
         int hashCode()
         返回此 collection 的哈希码值。
         boolean isEmpty()
         如果此 collection 不包含元素,则返回 trueint size()
         返回此 collection 中的元素数。       
     
          --------------------------------一些特殊的api-------------------------
         Object[] toArray()
         返回包含此 collection 中所有元素的数组。 
         <T> T[]  toArray(T[] a)
         返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。
//
         Iterator<E> iterator()
         返回在此 collection 的元素上进行迭代的迭代器。

  -------------------List自己还定义的根据下标操作的api  ---------------
         void add(int index, E element): 根据下标的添加方法     
         boolean addAll(int index, Collection<? extends E> c): 根据下标添加所有      
         E remove(int index): 删除指定下标位置的数据
         E get(int index): 根据下标查找下标位置的存储内容
         int indexOf(Object o): 根据内容查找下标
         int lastIndexOf(Object o): 根据内容查找下标(最后一个)
         E set(int index, E element):  根据下标, 替换指定下标位置的数据
  

listIterator: 是在Collection定义的iterator方法上的进一步增强, 可以向前遍历
         ListIterator<E> listIterator()
         返回此列表元素的列表迭代器(按适当顺序)。
         ListIterator<E> listIterator(int index)
         返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。

         List<E> subList(int fromIndex, int toIndex)
         返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。

subList

         List<E> subList(int fromIndex, int toIndex)
         返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。

注意: subList是一个视图方法:  所谓视图方法就是并没有真正获取/持有什么数据, 只是产生一个对象, 持有一些标记指向源数据(也就是看上去是subList从源数据切割出来一些数据, 但是实际上, 只是维护一些标记指向源数据)
    
注意: 视图方法也会产生并发修改异常 (怎么避免: 在使用视图结果的过程中, 不要调用源集合类修改结构的方法修改源集合数据)

在这里插入图片描述

4, ArrayList

4.1 ArrayList的特点

  1, ArrayListList的子实现
  2, ArrayList代表的数据结构是线性表
  3, ArrayList底层结构是数组
  4, 默认的初始长度 10,  默认的扩容机制扩为原来的1.5.
  5, ArrayList存储数据有序
  6, ArrayList存储元素允许重复
  7, ArrayList允许存储null
  8, ArrayList线程不安全

4.2 ArrayList的构造方法

ArrayList() 
          构造一个初始容量为 10 的空列表。 
ArrayList(Collection<? extends E> c) 
          构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。 
ArrayList(int initialCapacity) 
          构造一个具有指定初始容量的空列表。 

4.3 ArrayList的api

  ArrayList的api基本上完全参照List定义的api, 并没有额外增加很多api


  ------如下是ArrayList新定义的api(不是从List/collection继承的)-----------------------
Object clone(): 记忆一下
          返回此 ArrayList 实例的浅表副本。 
void ensureCapacity(int minCapacity): 了解即可
     如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 
void trimToSize(): 了解即可
     将此 ArrayList 实例的容量调整为列表的当前大小 

在这里插入图片描述

5, Vector

5.1 Vector的特点

  1, VectorList的子类
  2, Vector表示数据结构是线性表
  3, Vector的底层结构是数组
  4, 数组默认初始容量10, 
     默认扩容机制: 如果存在 增量(>0)扩容扩大增量个, 如果增量(<= 0), 扩为原来的25, 存储元素有序
  6, 允许存储重复元素
  7, 允许存储null
  8, 线程安全
  9, Vector是jdk1.0时候出现, ArrayListJdk1.2时候出现(ArrayList出现就是为了取代Vector)

6, Stack

  1, 如果我们真的使用了Stack, 虽然从语法上讲一个Stack对象完全可以使用add.remove方法, 但是建议不要使用(不是语法不可用),  建议使用push, pop, peek, 因为你希望Stack作为一个栈存在

  2, 如果我们在工作实际使用的时候如果需要一个栈的数据结构, 建议使用Deque, 不要使用时Stack

在这里插入图片描述

7, LinkedList

7.1 LinkedList的特点

  1, LinkedListList接口以及Deque接口子实现
  2, LinkedList数据结构:  普通线性表, 队列, 双端队列,3, 底层是一个双向链表
  4, 存储元素有序
  5, 允许存储重复数据
  6, 允许存储null
  7, 线程不安全

7.2 LinkedList的构造方法

LinkedList() 
          构造一个空列表。 
LinkedList(Collection<? extends E> c) 
          构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列。 

7.3 LinkedList的api

  --- LinkedList具有从Collection继承来的api: (添加删除相关, 集合类都具有,  三个特殊方法)----

  --- LinkedList 拥有从List继承来的根据下标操作的api:( 根据下标的增删改查, 两个特殊方法)

          --- LinkedListQueue接口继承来的重要方法 -------
         offer: 入队列方法
         poll:  出队列方法
         peek:  查看队头方法
         LinkedList<String> queue = new LinkedList<>();
         queue.offer("zs");
         queue.poll();
         queue.peek();
        
          ----LinkedListDeque继承来的作为双端队列的api -----
         offerFirst:  入队头
         offerLast: 入队尾
         pollLast:    出队尾
         pollFirst:   出队头
         peekLast:    查看队尾
         peekFirst: 查看队头
        
         LinkedList<String> deque = new LinkedList<>();
         deque.offerFirst("zs");
         deque.offerLast("ls");
         deque.offerFirst("wu");
         deque.offerLast("zl");
         deque.pollLast();
         deque.pollFirst();
         deque.peekLast();
         deque.peekFirst();


          ----LinkedListDeque继承来的作为栈的api -----
         push:  入栈
         pop:   出栈
         peek:  查看栈顶元素
         LinkedList<String> stack = new LinkedList<>();
         stack.push("zs");
         stack.pop();
         stack.peek();


在这里插入图片描述

8, Queue

8.1 Queue的特点

  1, Queue接口值Collection的子接口
  2, Queue表示的数据结构: 队列
  3, Queue存储元素有序
  4, Queue允许存储重复元素
  5, Queue不允许存储null ( 因为Queue子实现一般在删除的时候, 以返回null作为没有数据可以删除的标记, 所以如果queue允许存储null, 返回的时候, 会引起歧义, 所以不允许存储null)

   除了从Collection继承是api以外 -----

         offer: 入队列方法
         poll:  出队列方法
         peek:  查看队头方法

9, Deque

9.1 Deque的特点

  1, Deque接口是Queue接口的子接口
  2, Deque的数据结构:  队列, 双端队列,3, Deque存储元素有序
  4, Deque允许存储重复元素
  5, Deque不允许存储null (LinkedList除外)

api

   除了从Collection继承是api以外 -----

		  --- 作为队列 -------
         offer: 入队列方法
         poll:  出队列方法
         peek:  查看队头方法

          ----作为双端队列 -----
         offerFirst:  入队头
         offerLast: 入队尾
         pollLast:    出队尾
         pollFirst:   出队头
         peekLast:    查看队尾
         peekFirst: 查看队头


          ----作为栈的api -----
         push:  入栈
         pop:   出栈
         peek:  查看栈顶元素

在这里插入图片描述

10, ArrayDeque

10.1 ArrayDeque的特点

  1, ArrayDequeDeque接口的子实现
  2, ArrayDeque数据结构:  队列, 双端队列,3, ArrayDeque底层是一个循环数组
  4, 底层数组的默认初始长度: 16,  默认的扩容机制: 25, 存储元素有序
  6, 允许存储重复元素
  7, 不允许存储null
  8, 线程不安全
  9, 如果我们在构造方法中给ArrayDeque指定长度(大于等于8), 它会创建一个大于给定值的最小的2的幂值作为底层数组长度.  (如果给定值小于8 , 就创建一个长度为8的数组)   ---> 结合默认初始长度16 和扩容机制2倍的问题 ---> 保证ArrayDeque底层数组长度永远是2的幂值 --->  取模运算用&


  16 --> 32
  20 --> 32
  100 --> 128


在这里插入图片描述

11, BlockingQueue

  1, 什么是阻塞队列? 
       一个大小有容有限的队列
        添加的时候, 添加满了, 添加线程等待
        删除的时候, 队列空了, 删除线程等待

  2, BlockingQueue的阻塞方法有哪些? 
     一直阻塞:  put, take
     超时阻塞:  offer, poll
           

在这里插入图片描述

12, Map

12.1 Map的特点

   1, Map接口是Map集合体系的顶级接口
   2, Map存储的是key-value(键值对). 
   3, Map的有些子实现存储元素有序,  有些子实现存储元素无序
   4, Map的子实现都不允许存储重复数据
   5, Map的有些子实现允许存储null,  Map的有些子实现不允许存储null

12.2 Map的api

      ----增删改查相关-----
          V put(K key, V value): 添加
          void putAll(Map<? extends K,? extends V> m): 添加所有
          V remove(Object key): 根据key把key-value从map删除
          boolean containsKey(Object key): 判断某个key是否存在
          boolean containsValue(Object value): 判断某个value是否存在
          V get(Object key): 根据key获取value

           ----集合类都具有的辅助方法---------
          void clear()
          从此映射中移除所有映射关系(可选操作)。
          boolean equals(Object o)
          比较指定的对象与此映射是否相等。
          int hashCode()
          返回此映射的哈希码值。
          boolean isEmpty()
          如果此映射未包含键-值映射关系,则返回 trueint size()
          返回此映射中的键-值映射关系数。

           ----------------视图方法----------------
          Set<K> keySet(): 获得Map中存储数据的键集(获取Map所有的key)
          Collection<V> values(): 获取Map中所有的value
          Set<Map.Entry<K,V>> entrySet(): 获得Map所有的键值对集合

在这里插入图片描述

补充: HashMap

加密算法

Hash算法(散列算法): Hash算法不是加密算法

​ MD4, MD5, SHA1, SHA2, SHA3

MD5, SHA1 : 已经被证明不具有强抗碰撞性

123 ----- md5 -------> 202cb962ac59075b964b07152d234b70 (hash值)

身份证, 密码, 支付密码

密码:

admin

123 —> md5 -------> 202cb962ac59075b964b07152d234b70

456

Hash算法的特点:

1, 正向快速

2, 输入敏感

3, 冲突避免

4, 逆推困难( 碰撞困难 )

加盐: 盐值

在这里插入图片描述

13, HashMap: 重要

13.1 HashMap底层机构

HashMap: 底层是一个数组+链表+红黑树结构

(注意: 在jdk1.8之前, 是单纯的数组 + 链表 )

   HashMap的hash仅仅是想模拟hash算法的思想,  以达到""充分散列""的效果

   HashMap使用类似hash算法的思想,"希望"让一个key经过计算之后, 得到完全不同的int, 这个不同的key的int值经过取模之后, 下标也完全不同

请添加图片描述

13.2 HashMap的特点

   1, HashMapMap接口子实现
   2, HashMap的底层结构:  数组 + 链表 + 红黑树 (在jdk1.8之前是单纯的数组+链表)
   3, 数组的默认初始长度:16,  默认的扩容机制:2, 默认加载因子:0.75
   4, HashMap存储元素无序
   5, HashMap不允许存储重复的key:  (什么叫重复? )
   6, HashMap允许存储null作为key
   7, HashMap线程不安全

注意1: HashMap的加载因子

   HashMap它的默认的加载因子是0.75 (控制HashMap的阈值)
   我们可以通过加载因子控制阈值, 阈值控制什么时候扩容
 阈值 = 加载因子 *  数组长度
   12  =  16 *  0.75 
     
   如果HashMap存储的元素个数,超过阈值, HashMap的底层数组就要扩容
   注意: 虽然我们可以通过构造方法修改加载因子的参数, 但是不要乱改, 建议保证0.51之间最好是0.75

注意2: hash值取法

我们知道key-value数据存储到HashMap过程中, 我们是先根据key计算hash值,   hash值再和数组长度取余得下标. 
我们希望不同key经过计算之后, 取得下标不要相同, (在实际取余运算的过程中, 只有hash值的低位会起效果), 也就意味着我们希望hash值的低位尽可能随机(不要相同), 所以hash值的低位来源于一个key高位和低位异或的结果
       
    (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

   了解: hashCode不用, hash值有没可能相同? 

注意3: HashMap底层是一个Node类型的数组, 存储的是Node结点, Node结点里面包含key-value数据

Node还包含: hash值, next

 class Node<K,V>   {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
 }

注意4: HashMap对key的重复的定义

HashMap两个key如果hash值一样,  并且   key直接相等或者相equals, 就是重复, 不能存, 否就是不重复

if (p.hash == hash &&  ((k = p.key) == key || (key != null && key.equals(k))))

注意5: HashMap存储重复的key

   注意: 当新存储的key-value, key和某个已经存储的key-value经过判断重复,  会选择用新的value替换旧的value, 并且把旧value返回出来

注意6: HashMap链表过长转化为红黑树

   我们不希望在HashMap产生一个过长的链表(jdk1.8时候引入了红黑树), 当链表长度超过8达到9的时候(算上新添加的key-value构建的结点),   链表要转化为红黑树


注意7: HashMap中链表长度超过8, 达到9一定会转化为红黑树吗?

   不一定:  如果HashMap某个下标位置链表过长(超过8, 达到9),会触发树化操作(链表转化为树的操作), 如果数组长度是小于64, 优先扩容, 而非转化为红黑树

   当链表长度超过8达到9, 如果数组长度小于64, 会扩容,而非转化为红黑树
   当链表长度超过8达到9, 如果数组长度大于等于64, 会转化为红黑树

if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();

注意8: 扩容的时候, 数据重新散列

   由于HashMap底层数组是2的幂值, 扩容又扩为原来的2倍

假设旧数组长度为n,  原本在旧数组x下标位置的数据, 扩容之后重新散列: 要么还在x位置, 要么在n+x
两个位置可能

注意9: 添加key-value数据, 如果添加到某个下标位置, 这个下标位置是红黑树

   添加key-value数据, 如果添加到某个下标位置, 这个下标位置是红黑树, 要按照红黑树的逻辑添加
   红黑树是一个二叉搜索树, 要按照大小确定左右方向
   在HashMap某个下标位置的红黑树添加, 大小比较是按照key的hash值进行的
   如果比较过程中, 已经存储的某个结点key的hash值和当前新存储的key的hash一样, 进一步判断key是否直接相等或者相equals, 如果相等, 替换
   如果找到最底层都没有找到一个相等的hash, 直接存储个新的结点到树上


了解: 如果在树上比较的过程中, hash值一样, 但是key不相等也不相equals, 怎么处理?   

注意10 : 红黑树转化为链表

//1, 如果我们在HashMap上删除数据的时候, 一直删除的是红黑树上的结点, 导致红黑树上存储key-value数据变少, 红黑树要转化为链表
  当红黑树中根结点, 或者根结点左右结点,  或者根结点的左结点的左结点, 这四个结点有一个不存在, 就要由红黑树转化为链表

if (root == null || root.right == null ||  (rl = root.left) == null || rl.left == null) 
    
   2, 扩容, 某一个下标位置红黑树的数据拆成两部分, 如果某一部分数据量过少, 就会有的红黑树转化为链表
    扩容, 某一个下标位置红黑树的数据拆成两部分, 任一部分的key-value数据量, 小于等于6, 就要由红黑树转化为链表
    
    hc <= UNTREEIFY_THRESHOLD(6)

注意11: 为什么链表转化为红黑树阈值设为8, 而红黑树转化为链表阈值设为6?

   如果问了, 怎么答:  不希望链表和红黑树反复因为添加和删除反复相互转化. 

注意12: 给定HashMap长度

   如果我们在构造方法里,HashMap指定长度, 实际上HashMap的底层会创建一个大于等于给定值的最小的2的幂值作为底层数组长度 (ArrayDeque不同)

16 --> 16
20 --> 32
    
这个特点和默认初始长度16 以及扩容机制2---> 数组底层是2的幂值
    

注意13:

   如果一个key-value数据已经存储到HashMap中了,  而且key还重写了hashCode以及equals方法, 那就不要在通过key的引用来直接修改key, 有可能访问不到

HashMap添加一个数据的大致流程

   1, 有一份key-value数据, 要添加的HashMap2, 取出key 计算 hash值 ((h = key.hashCode()) ^ (h >>> 16);)
       取一位和异或运算的原因是希望充分散列/尽量不冲突
   3, 用计算的hash值和数组长度取模: (n - 1) & hash
      推出一个隐含的结论, 在取模计算中 只有hash值的低位会起效果
   4, 根据上一步计算的下标, 判断这个下标位置是否已经存储了内容, 如果没有存储内容, 直接创建一个结点存储到这个下标位置
           结点是Node类型, 包含: key,value, hash,next四个参数
   5,  根据上一步(3)计算的下标, 这个下标位置可能已经存储了元素:  先判断是否重复
            hash一样; 并且,  两个key要么直接相等, 要么相equals
			p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))
        5.1 如果key值重复了, 新的key-value的value值覆盖旧值   
        5.2 如果key值不重复, 接着按照链表向下比较, 在遍历链表的过程中还是判断链表中的及诶单是否重复, (重复了, 新值覆盖旧值)
            如果在这个链表比较的过程中, 一直不重复, 把这份新的key-value数据,构建一个结点,添加到这个链表的尾部
   6, 如果在这个下标位置, 不重复, 添加(构建链表)(5.2步骤), 如果添加一个元素之后, 导致链表过程(超过8, 达到9), 那么添加完成之后, 这个链表要转化为红黑树
           如果转化红黑树的过程中, 发现数组长度小于64, 选择扩容(元素重新按照新长度散列问题), 而非转化为红黑树
          
   7, 假设上述步骤添加成功一份key-value数据:  有可能引起扩容 (整体存储的数据超过阈值)
                
   8, 上述所有的扩容, 都有可能导致原本数组某个位置如果有红黑树, 红黑树被拆成两部分(低位和高位), 任一位置结点数变少, 又有可能导致红黑树转化为链表
                

13.3 HashMap的构造方法

HashMap() 
          构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMapHashMap(int initialCapacity) 
          构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMapHashMap(int initialCapacity, float loadFactor) 
          构造一个带指定初始容量和加载因子的空 HashMapHashMap(Map<? extends K,? extends V> m) 
          构造一个映射关系与指定 Map 相同的新 HashMap

13.4 HashMap的api

   HashMap的api基本上完全遵照Map接口的定义

在这里插入图片描述

14, LinkedHashMap

14.1 LinkedHashMap的特点

 1, LinkedHashMapHashMap的子类
 2, LinkedHashMap底层结构和HashMap保持一直(LinkedHashMap复用了父类的结构和方法)
 3, LinkedHashMapHashMap的基础上额外维护了一个双向链表--> 保证迭代顺序
 4, LinkedHashMap存储元素有序
 5, 不允许存储重复的key
 6, 允许存储null
 7, 线程不安全

14.2 LinkedHashMap的构造方法

LinkedHashMap() 
          构造一个带默认初始容量 (16) 和加载因子 (0.75) 的空插入顺序 LinkedHashMap 实例。 
LinkedHashMap(int initialCapacity) 
          构造一个带指定初始容量和默认加载因子 (0.75) 的空插入顺序 LinkedHashMap 实例。 
LinkedHashMap(int initialCapacity, float loadFactor) 
          构造一个带指定初始容量和加载因子的空插入顺序 LinkedHashMap 实例。 
LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 
          构造一个带指定初始容量、加载因子和排序模式的空 LinkedHashMap 实例。 
LinkedHashMap(Map<? extends K,? extends V> m) 
          构造一个映射关系与指定映射相同的插入顺序 LinkedHashMap 实例。 

14.3 LinkedHashMap的api

 LinkedHashMap没有在HashMap的基础上额外定义什么api,  HashMap的api基本上完全遵照Map接口的定义

15, Hashtable

15.1 Hashtable的特点

 1, HashtableMap接口的子实现
 2, Hashtable底层结构: 数组 + 链表   (HashMap在jdk1.8之前一样)
 3, 默认初始容量11,  默认扩容机制: 2+1
 4, 存储数据无序
 5, 不允许存储重复的key:  hash一样并且  key直接相等或者相equals 就是重复
 6, 不允许存储null作为key, 也不允许存储null作为value
 7, Hashtable线程安全
 8, Hashtable是jdk1.0,  HashMap是jdk1.2出现

在这里插入图片描述

16, TreeMap

16.1 TreeMap的特点

 1, TreeMapMap接口的子实现
 2, TreeMap数据结构是一个红黑树 (底层用链表表示)
 3, 存储元素: 大小有序
 4, 不允许存储重复的key: key大小重复(hash没有关系)
 5, 不允许存储null作为key:   null没有办法比较大小
 6, 线程不安全

16.2 TreeMap的构造方法

TreeMap() 
          使用键的自然顺序构造一个新的、空的树映射。 
TreeMap(Comparator<? super K> comparator) 
          构造一个新的、空的树映射,该映射根据给定比较器进行排序。 
TreeMap(Map<? extends K,? extends V> m) 
          构造一个与给定映射具有相同映射关系的新的树映射,该映射根据其键的自然顺序 进行排序。 
TreeMap(SortedMap<K,? extends V> m) 
          构造一个与指定有序映射具有相同映射关系和相同排序顺序的新的树映射。 

16.3 TreeMap的api

    ----------------------Map接口继承来的----------------------------
        boolean containsKey(Object key)
        如果此映射包含指定键的映射关系,则返回 trueboolean containsValue(Object value)
        如果此映射为指定值映射一个或多个键,则返回 trueV put(K key, V value)
        将指定值与此映射中的指定键进行关联。
        void putAll(Map<? extends K,? extends V> map)
        将指定映射中的所有映射关系复制到此映射中。
        V remove(Object key)
        如果此 TreeMap 中存在该键的映射关系,则将其删除。
        V get(Object key)
        返回指定键所映射的值,如果对于该键而言,此映射不包含任何映射关系,则返回 nullvoid clear()
        从此映射中移除所有映射关系。
        Object clone()
        返回此 TreeMap 实例的浅表副本。
        int size()
        返回此映射中的键-值映射关系数。


        Collection<V> values()
        返回此映射包含的值的 Collection 视图。
        Set<K> keySet()
        返回此映射包含的键的 Set 视图。
        Set<Map.Entry<K,V>> entrySet()
        返回此映射中包含的映射关系的 Set 视图。      
        
         ------------------------TreeMap定义大小操作相关的api------------------------
        Map.Entry<K,V> ceilingEntry(K key): 大于等于给定key的最小键值对
        K ceilingKey(K key): 大于等于给定key的最小key
        Map.Entry<K,V> floorEntry(K key): 小于等于key的最大的键值对
        K floorKey(K key): 小于等于key最大的key
        Map.Entry<K,V> higherEntry(K key): 大于给定key的最小键值对
        K higherKey(K key): 大于给定key的最小key
        Map.Entry<K,V> lowerEntry(K key): 小于key的最大的键值对
        K lowerKey(K key): 小于key最大的key

        Map.Entry<K,V> firstEntry(): 返回最小的键值对
        K firstKey(): 返回最小的key
        Map.Entry<K,V> lastEntry(): 返回最大的键值对
        K lastKey(): 返回最大的key

        Map.Entry<K,V> pollFirstEntry(): 删除最小的键值对
        Map.Entry<K,V> pollLastEntry(): 删除最大的键值对


         ---------------------视图方法-----------------------------
        NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
        返回此映射的部分视图,其键的范围从 fromKey 到 toKey。
        SortedMap<K,V> subMap(K fromKey, K toKey)
        返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。
        SortedMap<K,V> tailMap(K fromKey)
        返回此映射的部分视图,其键大于等于 fromKey。
        NavigableMap<K,V> tailMap(K fromKey, boolean inclusive)
        返回此映射的部分视图,其键大于(或等于,如果 inclusive 为 true)fromKey。
        SortedMap<K,V> headMap(K toKey)
        返回此映射的部分视图,其键值严格小于 toKey。
        NavigableMap<K,V> headMap(K toKey, boolean inclusive)
        返回此映射的部分视图,其键小于(或等于,如果 inclusive 为 true)toKey。

         -------------------------一些特殊的api: 了解-------------------------------
        NavigableSet<K> descendingKeySet()
        返回此映射中所包含键的逆序 NavigableSet 视图。
        NavigableMap<K,V> descendingMap()
        返回此映射中所包含映射关系的逆序视图。
        NavigableSet<K> navigableKeySet()
        返回此映射中所包含键的 NavigableSet 视图。
        Comparator<? super K> comparator()
        返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回 null

在这里插入图片描述

17, Set

17.1 Set的特点

 1, Set接口是Collection的子接口
 2, Set数据结构集合
 3, Set有些子实现有序, 有些子实现无序
 4, Set不允许存储重复key数据
 5, Set有些子实现允许存储null, 有些子实现不允许存储null

17.2 Set的api

 Set接口的api 完全复用Collection的定义, 并没有在增加什么api

18, HashSet

18.1 HashSet的特点

 1, HashSetSet接口子实现
 2, HashSet底层持有一个HashMap对象;  我们存储到HashSet上的数据, 实际都存储到底层持有的HashMap的key上了.
 3, HashSet特点和HashMap的key的特点保持一致
 4, HashSet存储元素无序
 5, HashSet不允许存储重复元素:  hash一样  并且  数据直接相等或者相equals 
 6, HashSet允许存储null
 7, 线程不安全

18.2 HashSet的构造方法

HashSet() 
          构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75HashSet(Collection<? extends E> c) 
          构造一个包含指定 collection 中的元素的新 set。 
HashSet(int initialCapacity) 
          构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。 
HashSet(int initialCapacity, float loadFactor) 
          构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。 

18.3 HashSet的api

 HashSet的api和Set接口保持一直,   Set接口的api 完全复用Collection的定义, 并没有在增加什么api

在这里插入图片描述

19, LinkedHashSet

19.1 LinkedHashSet的特点

 1, LinkedHashSetHashSet的子类
 2, LinkedHashSet底层持有一个LinkedHashMap
       也就意味着LinkedHashSet的特点和LinkedHashMap的key一致
 3, LinkedHashSet存储数据有序
 4, 不允许存储重复数据
 5, 允许存储null
 6, 线程不安全

19.2 LinkedHashSet 的构造方法

LinkedHashSet() 
          构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set。 
LinkedHashSet(Collection<? extends E> c) 
          构造一个与指定 collection 中的元素相同的新链接哈希 set。 
LinkedHashSet(int initialCapacity) 
          构造一个带指定初始容量和默认加载因子 (0.75) 的新空链接哈希 set。 
LinkedHashSet(int initialCapacity, float loadFactor) 
          构造一个带有指定初始容量和加载因子的新空链接哈希 set。 

19.3 LinkedHashSet的api

 LinkedHashSet / HashSet的api和Set接口保持一致,   Set接口的api 完全复用Collection的定义, 并没有在增加什么api

在这里插入图片描述

20, TreeSet

20.1 TreeSet的特点

 1, TreeSetSet接口子实现
 2, TreeSet底层是一个TreeMap对象
      意味着存储的到TreeSet上的数据, 会存储TreeSet底层持有TreeMap的key上, TreeSet的特点和TreeMap的key保持一直
 3, TreeSet存储数据大小有序
 4, TreeSet不允许存储重复数据:  大小重复
 5, TreeSet不允许存储null: 没有办法比较大小
 6, 线程不安全

20.2 TreeSet的构造方法

构造方法摘要 
TreeSet() 
          构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。 
TreeSet(Comparator<? super E> comparator) 
          构造一个新的空 TreeSet,它根据指定比较器进行排序。 
    
TreeSet(Collection<? extends E> c) 
          构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。 
TreeSet(SortedSet<E> s) 
          构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet

20.3 TreeSet的api

  ------------------------------------Collection定义---------------
        boolean add(E e)
        将指定的元素添加到此 set(如果该元素尚未存在于 set 中)。
        boolean addAll(Collection<? extends E> c)
        将指定 collection 中的所有元素添加到此 set 中。
        boolean contains(Object o)
        如果此 set 包含指定的元素,则返回 trueboolean remove(Object o)
        将指定的元素从 set 中移除(如果该元素存在于此 set 中)。


        void clear()
        移除此 set 中的所有元素。
        Object clone()
        返回 TreeSet 实例的浅表副本。
        boolean isEmpty()
        如果此 set 不包含任何元素,则返回 trueint size()
        返回 set 中的元素数(set 的容量)。


        Iterator<E> iterator()
        返回在此 set 中的元素上按升序进行迭代的迭代器。


 -----------------------------大小操作相关----------------------

        E ceiling(E e): 返回大于等于的给定值
        E floor(E e): 返回小于等于的给定值
        E higher(E e): 返回大于的给定值
        E lower(E e): 返回小于的给定值
        E first(): 获取最小的值
        E last(): 获取最大的值
        E pollFirst(): 删除最小的/第一个元素
        E pollLast(): 删除最大/最后一个元素


        NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
        返回此 set 的部分视图,其元素范围从 fromElement 到 toElement。
        SortedSet<E> subSet(E fromElement, E toElement)
        返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
        SortedSet<E> tailSet(E fromElement)
        返回此 set 的部分视图,其元素大于等于 fromElement。
        NavigableSet<E> tailSet(E fromElement, boolean inclusive)
        返回此 set 的部分视图,其元素大于(或等于,如果 inclusive 为 true)fromElement。
        SortedSet<E> headSet(E toElement)
        返回此 set 的部分视图,其元素严格小于 toElement。
        NavigableSet<E> headSet(E toElement, boolean inclusive)
        返回此 set 的部分视图,其元素小于(或等于,如果 inclusive 为 true)toElement。

 ----------------------------------------------其它----------------
        Comparator<? super E> comparator()
        返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 nullIterator<E> descendingIterator()
        返回在此 set 元素上按降序进行迭代的迭代器。
        NavigableSet<E> descendingSet()
        返回此 set 中所包含元素的逆序视图。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值