Java容器

瘦欲@ 提交于 2020-03-04 16:22:48

Java容器

Java中容器类可以分为两大类:Collection与Map。

  • Collection:存储对象的集合;
  • Map:存储键值对。

Collection

Set

TreeSet

基于红黑树,支持有序性操作。

HashSet

基于哈希表实现,支持快速查找,不支持有序性操作。

LinkedHashSet

基于双向链表实现,只能顺序访问,可以快速在其中间插入和删除元素。


List

ArrayList

基于动态数组实现,支持随机访问。

ArrayList源码

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//基于数组实现,RandomAccess表示支持随机访问。

private static final int DEFAULT_CAPACITY = 10;
//默认大小为10

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
//int newCapacity = oldCapacity + (oldCapacity >> 1); 表示每次扩容为旧容量的1.5倍。

transient Object[] elementData;
//使用transient修饰,默认数组不会被序列化。

Vector

和ArrayList相似,是线程安全的(除了私有方法,其他方法都使用了synchronized修饰)。

    public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    }

    public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }

    public synchronized int capacity() {
        return elementData.length;
    }

    public synchronized boolean isEmpty() {
        return elementCount == 0;
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
//扩容的时候看传入的参数,如果大于0就扩大为原来基础上加上你传入的参数,如果小于0就扩大为原来的两倍(实际开发中因该很少调用构造函数,所以大多数情况是扩大为原来的两倍)。

``

LinkedList

基于双向链表实现,只能顺序访问,但是可以快速在链表中间插入和删除元素。

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
//使用双向链表且每个节点存储了上下两个节点。

transient Node<E> first;
transient Node<E> last;
//每个链表存储了first和last指针

Queue

LinkedList

常用于实现双向队列

PriorityQueue

基于堆结构实现,可以实现优先队列。


Map

TreeMap

基于红黑树实现

HashMap

基于哈希表实现
在jdk1.7及以前的时候使用的是数组和链表,在jdk1.8及以后使用的是数组、链表和红黑树。

transient Entry[] table;
//不会被序列化

拉链法

HashMap<String, String> map = new HashMap<>();
map.put("K1", "V1");
map.put("K2", "V2");
map.put("K3", "V3");
  • 新建一个 HashMap,默认大小为 16;
  • 插入 <K1,V1> 键值对,先计算 K1 的 hashCode 为 115,使用除留余数法得到所在的桶下标 115%16=3。
  • 插入 <K2,V2> 键值对,先计算 K2 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6。
  • 插入 <K3,V3> 键值对,先计算 K3 的 hashCode 为 118,使用除留余数法得到所在的桶下标 118%16=6,插在 <K2,V2> 前面。

注意:链表的插入是头插法的方式进行的。

查找:

  • 计算键值对所在的桶;
  • 在链表上顺序查找,时间复杂度显然和链表的长度成正比。

扩容的时候扩大为原来的2倍。

void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<>(hash, key, value, e);
    if (size++ >= threshold)
        resize(2 * table.length);
}

HashTable

与HashMap类似,是线程安全的,但不推荐使用(推荐使用ConcurrentHashMap)

LinkedHashMap

使用双向链表来维护元素的顺序,顺序插入顺序或者最近最少使用(LRU)顺序。
继承HashMap

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!