Java集合知识点

1. Java集合分类

Java集合可分为两大类:CollectionMap
集合的数据结构主要有两种:数组链表
数组常用于查询多、修改删除少的场景
链表常用于修改删除多、查询少的场景
在这里插入图片描述

2. 集合特点整理

2.1 List

2.1.1 ArrayList

特点:数据不唯一、有序;
优点:随机索引查询速度快
缺点:随机插入删除数据效率低

ArrayList有两个重要的属性:Object数组(elementData)、size;ArrayList实例化的时候如果没有设置初始大小的时候,Object数组会赋值一个空数组,只有执行put的时候才会初始化一个长度为10的数组;当size大于elementData的长度,List会进行扩容至原来的1.5倍。
ArrayList扩容会进行数组数据转移,会耗费一定的时间,所以当已知数组的长度可以在初始化的时候给定长度。

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

2.1.2 LinkedList

优点:随机插入删除效率比数组高
缺点:随机索引查询效率比数组低

  • LinkedList是双向链表实现的List、非线程安全、其元素允许null及重复元素
  • LinkedList基于链表实现,所以不存在容量不足的情况,也就没有扩容的方法
    transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

    /**
     * Constructs an empty list.
     */
    public LinkedList() {
    }

2.2 Set

2.2.1 HashSet

特点: 元素具有唯一性、无序性

HashSet是由数组+链表构成(HashMap);数据唯一性判定先通过hashCode()判断,再通过equals校验;使用hashCode的原因是为了提高比较检索速度。

private transient HashMap<E,Object> map;

 // Dummy value to associate with an Object in the backing Map
 private static final Object PRESENT = new Object();

 /**
  * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
  * default initial capacity (16) and load factor (0.75).
  */
 public HashSet() {
     map = new HashMap<>();
 }
2.2.2 LinkedHashSet

特点:元素具有唯一性、有序性(按插入顺序)
LinkedHashSet是HashSet的子类,通过数组+链表的方式保证元素的唯一性,再次基础上加上一个双向链表来确保元素按照插入顺序进行排序(LinkedHashMap);因为有一个双端队列,所以在插入元素方面略低于HashSet,但是在迭代访问的时候不受影响。

# LinkedHashSet类 
 /**
  * Constructs a new, empty linked hash set with the default initial
  * capacity (16) and load factor (0.75).
  */
 public LinkedHashSet() {
     super(16, .75f, true);
 }
#HashSet类
   /**
    * Constructs a new, empty linked hash set.  (This package private
    * constructor is only used by LinkedHashSet.) The backing
    * HashMap instance is a LinkedHashMap with the specified initial
    * capacity and the specified load factor.
    *
    * @param      initialCapacity   the initial capacity of the hash map
    * @param      loadFactor        the load factor of the hash map
    * @param      dummy             ignored (distinguishes this
    *             constructor from other int, float constructor.)
    * @throws     IllegalArgumentException if the initial capacity is less
    *             than zero, or if the load factor is nonpositive
    */
   HashSet(int initialCapacity, float loadFactor, boolean dummy) {
       map = new LinkedHashMap<>(initialCapacity, loadFactor);
   }
2.2.3 TreeSet

特点: TreeSet实现SortedSet接口,可以保证元素的排序状态。

TreeSet底层使用红黑树结构存储数据。
TreeSet有两种排序方法: 自然排序和定制排序。默认情况下,TreeSet采用自然排序

    /**
     * Constructs a new, empty tree set, sorted according to the
     * natural ordering of its elements.  All elements inserted into
     * the set must implement the {@link Comparable} interface.
     * Furthermore, all such elements must be <i>mutually
     * comparable</i>: {@code e1.compareTo(e2)} must not throw a
     * {@code ClassCastException} for any elements {@code e1} and
     * {@code e2} in the set.  If the user attempts to add an element
     * to the set that violates this constraint (for example, the user
     * attempts to add a string element to a set whose elements are
     * integers), the {@code add} call will throw a
     * {@code ClassCastException}.
     */
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    /**
     * Constructs a new, empty tree set, sorted according to the specified
     * comparator.  All elements inserted into the set must be <i>mutually
     * comparable</i> by the specified comparator: {@code comparator.compare(e1,
     * e2)} must not throw a {@code ClassCastException} for any elements
     * {@code e1} and {@code e2} in the set.  If the user attempts to add
     * an element to the set that violates this constraint, the
     * {@code add} call will throw a {@code ClassCastException}.
     *
     * @param comparator the comparator that will be used to order this set.
     *        If {@code null}, the {@linkplain Comparable natural
     *        ordering} of the elements will be used.
     */
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

2.3 Queue

Queue分为三大类:继承Queue接口的BlockingQueue(阻塞队列)、Deque(双端队列),抽象实现Queue的AbstractQueue(非阻塞队列)
特点:先进先出(FIFO)

在这里插入图片描述

图中我们能看到最上层是Collection 接口,Queue满足了集合类的所有类的方法,都是非阻塞式的

add(E e):增加元素,容量受限队列没有空间使用add会抛出IllegalStateException异常
offer(E e):增加元素,容量受限队列没有空间使用offer不会抛出异常
remove(Object o):删除元素,如果队列为空,会引起异常
poll():检索并删除队列头,如果队列为空,则返回null
element():检索但不删除队列头,如果队列为空,会引起异常
peek():检索但不删除队列头,如果队列为空,则返回null
clear():清除集合中所有元素;
size():集合元素的大小;
isEmpty():集合是否没有元素;
contains(Object o):集合是否包含元素o。

BlockingQueue接口继承至Queue接口,拓展了一些方法:

put(E e):插入元素 //阻塞
take():移除元素//阻塞
2.3.1 Deque

Deque在Queue的基础上,增加了下面几个方法:

addFirst(E e):在前端插入元素,异常处理和add一样;
addLast(E e):在后端插入元素,和add一样的效果;
offerFirst(E e):在前端插入元素,异常处理和offer一样;
offerLast(E e):在后端插入元素,和offer一样的效果;
removeFirst():移除前端的一个元素,异常处理和remove一样;
removeLast():移除后端的一个元素,和remove一样的效果;
pollFirst():移除前端的一个元素,和poll一样的效果;
pollLast():移除后端的一个元素,异常处理和poll一样;
getFirst():获取前端的一个元素,和element一样的效果;
getLast():获取后端的一个元素,异常处理和element一样;
peekFirst():获取前端的一个元素,和peek一样的效果;
peekLast():获取后端的一个元素,异常处理和peek一样;
removeFirstOccurrence(Object o):从前端开始移除第一个是o的元素;
removeLastOccurrence(Object o):从后端开始移除第一个是o的元素;
push(E e):和addFirst一样的效果;
pop():和removeFirst一样的效果。
2.3.2 阻塞队列
2.3.2.1 BlockingQueue

阻塞队列(BlockingQueue)支持put和take方法:put是当队列满时,存储元素线程会等待队列可用;take是当队列为空时,获取元素的线程会等待队列非空。
阻塞队列提供了四种方法:

方法异常抛出方法返回特殊值阻塞超时退出
插入方法add(e),队列满,抛出IIIegaISlabEepeplian异常offer(e),队列满,返回falseput(e),队列满一直阻塞offer(e,time,unit)
移除方法remove(),队列空,抛出IIIegaISlabEepeplian异常poll(),队列空,返回falsetake(),队列空一直阻塞poll(time,unit)
检查方法element(),队列空,抛出IIIegaISlabEepeplian异常peek(),队列空,返回false
  • 阻塞
    当阻塞队列满时,如果生产者线程往队列中put元素,队列会一直阻塞生产者线程,直到队列有空位,让元素插入到队列中或者响应中断停止
    当阻塞队列空时,如果消费者线程从队列中take元素,队列会阻塞线程,直到拿到队列中的元素
  • 超时退出
    当阻塞队列满时,offer(e,time,unit)插入元素,队列会阻塞生产者线程一段时间,超过设置的时间,生产线程就会退出
    当阻塞队列空时,poll(time,unit)移除元素,队列会阻塞消费者线程一段时间,超过设置的时间,消费者线程就会退出

阻塞队列成员:

队列有界性数据结构
ArrayBlockingQueuebounded(有界)加锁数组
LinkedBlockingQueueoptionally-bounded(默认Integer.MAX_VALUE,最好重新设置值)加锁链表
PriorityBlockingQueueunbounded加锁
DelayQueueunbounded加锁
SynchronousQueueunbounded加锁
LinkedTransferQueueunbounded加锁
LinkedBlockingDequeunbounded无锁
2.3.2.2 BlockingDeque

BlockingDeque(阻塞双端队列)在Deque的基础上实现了双端阻塞等待的功能。实现类:LinkedBlockingDeque

2.3.2.3 TransferQueue

TransferQueue比BlockingQueue更强大的一点是,生产者会一直阻塞到添加到队列的元素被某一个消费者消费 。阻塞发生在元素从一个线程transfer到另外一个线程的过程中,有效地实现了元素在线程间的传递。
接口提供的标准方法:

tryTransfer(E e):若当前存在一个正在等待获取的消费者线程(使用take()或者poll()函数),使用该方法会即刻转移/传输对象元素e并立即返回true;若不存在,则返回false,并且不进入队列。这是一个不阻塞的操作。
transfer(E e):若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素e到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。
tryTransfer(E e, long timeout, TimeUnit unit):若当前存在一个正在等待获取的消费者线程,会立即传输给它;否则将插入元素e到队列尾部,并且等待被消费者线程获取消费掉;若在指定的时间内元素e无法被消费者线程获取,则返回false,同时该元素被移除。
hasWaitingConsumer():判断是否存在消费者线程。
getWaitingConsumerCount():获取所有等待获取元素的消费线程数量。
2.3.3 非阻塞队列

非阻塞队列:PriorityQueueConcurrentLinkedQueue

  • PriorityQueue 类实质上维护了一个有序列表。加入到 Queue 中的元素根据它们的天然排序(通过其 java.util.Comparable 实现)或者根据传递给构造函数的 java.util.Comparator 实现来定位。

  • ConcurrentLinkedQueue 是基于链接节点的、线程安全的队列。并发访问不需要同步。因为它在队列的尾部添加元素并从头部删除它们,所以只要不需要知道队列的大 小,ConcurrentLinkedQueue 对公共集合的共享访问就可以工作得很好。收集关于队列大小的信息会很慢,需要遍历队列。入队和出队操作均利用CAS(compare and set)更新,这样允许多个线程并发执行,并且不会因为加锁而阻塞线程,使得并发性能更好。

2.4 Map

Map是一个接口,由key-value键值对构成,Map中不能包含重复的key,一个key最多对应一个值。

2.4.1 HashMap

HashMap底层是数组+链表;

    /**
    * Constructs an empty <tt>HashMap</tt> with the specified initial
    * capacity and load factor.
    *
    * @param  initialCapacity the initial capacity
    * @param  loadFactor      the load factor
    * @throws IllegalArgumentException if the initial capacity is negative
    *         or the load factor is nonpositive
    */
   public HashMap(int initialCapacity, float loadFactor) {
       if (initialCapacity < 0)
           throw new IllegalArgumentException("Illegal initial capacity: " +
                                              initialCapacity);
       if (initialCapacity > MAXIMUM_CAPACITY)
           initialCapacity = MAXIMUM_CAPACITY;
       if (loadFactor <= 0 || Float.isNaN(loadFactor))
           throw new IllegalArgumentException("Illegal load factor: " +
                                              loadFactor);
       this.loadFactor = loadFactor;
       this.threshold = tableSizeFor(initialCapacity);
   }

   /**
    * Constructs an empty <tt>HashMap</tt> with the specified initial
    * capacity and the default load factor (0.75).
    *
    * @param  initialCapacity the initial capacity.
    * @throws IllegalArgumentException if the initial capacity is negative.
    */
   public HashMap(int initialCapacity) {
       this(initialCapacity, DEFAULT_LOAD_FACTOR);
   }
    /**
    * Constructs an empty <tt>HashMap</tt> with the default initial capacity
    * (16) and the default load factor (0.75).
    */
   public HashMap() {
       this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
   }
   

HashMap初始化如果带入的不是map数据,那么初始化只会设定初始容量及负载因子数据,数组之类的并不会初始化;HashMap具体内容的初始化发生在put插入数据时。初始容量设定会根据tableSizeFor方法找到第一个大于等于initialCapacity的2的平方数,用于作为初始化table。之所以要table为2的倍数,是为了indexFor方法取下标的时候,h & (length-1)能取代mod更快实现下标取值。
threshold 是HashMap进行扩容的阈值,当HashMap存储的元素个数超过这个阈值的时候,就会进行扩容。阈值threshold=当前容量capacity*负载因子loadFactor。
当HashMap扩容时,容量会变成原来的两倍,原来存储的元素会重新计算哈希值,位置也会发生变化,这比较耗费性能,所以如果提前知道Map的size,可以在一创建的时候设定合适的大小减少resize开销。

2.4.2 LinkedHashMap

LinkedHashMap = HashMap + 双向链表
LinkedHashMap的存储顺序是按照调用put方法插入的顺序进行排序的。
LinkedHashMap有插入顺序和访问顺序两种。

2.4.3 ConCurrentHashMap

主要在多线程中用,解决HashMap可能会导致死锁问题,ConCurrentHashMap既可以保持同步也可以提高并发效率
ConCurrentHashMap关于扩容需要知道两个重要的参数:

  • MIN_TREEIFY_CAPACITY : 最小树形化容量阈值,默认为64
  • TREEIFY_THRESHOLD : 树化阈值,指定桶位链表长度达到8的话,就可能发生树化操作
    当元素个数大于最小树形化容量阈值并且链表长度大于8,才会调用treeifyBin()把链表转换成红黑树,否则会进行扩容操作。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值