集合框架简单整理

List

ArrayList 和 Vector 底层使用的是数组进行存储,查询快增删慢,因为在增加时需要考虑数组的扩容问题,在扩容和删除时需要对数组进行重新拷贝新的数组。不同之处在于 ArrayList 是线程不安全的,Vector 线程是安全的。

LinkedList 底层采用的是双向列表结构,通过node节点中维护next节点和prev 节点来维护顺序

ArrayList

arrayList 是一个可变长度的动态数组,默认初始化的时候长度是0,

当进行add操作时,会判断数组是否为空,如果为空,默认初始化10个长度

当数组的长度已使用完毕后,再次执行add方法时,会进行数组的扩容,

新的扩容长度为 原来数组长度的1.5倍

public ArrayList() {
    this.elementData = {};
}
// 扩容
private void grow(int minCapacity) {
    // overflow-conscious code
    // 判断旧的数组长度,新初始化的时候长度是0
    int oldCapacity = elementData.length;
    // 获得要扩容的新数组的长度:默认是原来的1.5倍
    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);
}

Vector

相比 ArrayList 来说,是线程安全的,是synchronized修饰的。结构和ArrayList 相同

vector 初始化的时候,默认初始化的数组长度是10,

当数组的商都使用完毕后,再次执行add方法时,会进行数组的扩容

新的数组为原来的1倍 或 扩容基础加上旧的数组长度

// 该构造方法,指定 初始化的数组长度,和扩容基础大小
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    this.elementData = new Object[initialCapacity];
    // 扩容基础大小
    this.capacityIncrement = capacityIncrement;
}

// 扩容
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    // 当使用无参构造Vector 或一个参数时, capacityIncrement 为0 ,
    // 默认新的数组大小 = 旧的数组大小 + 旧的数组大小 即:扩容一倍
    // 如果指定了扩容基础大小,则新的数组大小 = 旧的数组大小 + capacityIncrement
    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);
}

LinkedList

linkedList 底层采用的是双向的链表结构,通过next 、prev node 节点组成双向链表结构

transient Node<E> first;
transient Node<E> last;

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;
    }
}
//添加节点到最后一个节点上
void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
}

Map

HashMap 、ConcurrentHashMap 无序集合,不同之处在于ConcurrentHashMap是线程安全的,并且不允许key和value 为空。

LinkedHashMap 和 TreeMap是有序集合,LinkedHashMap 有序是通过节点维护 before和 after 节点属性,而TreeMap 是通过实现了SortedMap

HashMap 可以key 、value 为空,线程不安全,HashTable 不能为空,线程安全

HashMap 参考 HashMap 源码分析学习

LinkedHashMap 参考 LinkedHashMap 源码分析学习

TreeMap

TreeMap 有序集合,实现了SortedMap,并且又可以通过构造传入排序的算法,默认按照key的排序规则进行排序,如果没有指定规则排序,则使用key 的类型所默认的类型排序规则进行排序,如果指定了自定义的排序规则,则使用自定义的规则

// 无自定义规则,使用默认的排序规则
public TreeMap() {
    comparator = null;
}
// 使用自定义的排序规则
public TreeMap(SortedMap<K, ? extends V> m) {
    comparator = m.comparator();
    try {
        buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
    } catch (java.io.IOException cannotHappen) {
    } catch (ClassNotFoundException cannotHappen) {
    }
}
// Entry 内部类,扩展了 left、right、parent 使之有序
static final class Entry<K,V> implements Map.Entry<K,V> {
    K key;
    V value;
    Entry<K,V> left;
    Entry<K,V> right;
    Entry<K,V> parent;
}

ConcurrentHashMap

ConcurrentHashMap 的节点与HashMap 的节点大致是相同的,都是继承了Map.Entry,不同之处在于在ConcurrentHashMap.Node 节点的val 和 next 属性被 volatile 进行修饰。并大量使用了 Unsafe类 和 CAS 的安全替换.

transient volatile Node<K,V>[] table;  
static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;
}

HashTable

Hashtable 不允许key、value为空,扩容时是原来的2倍+1,没有红黑树的概念

// 默认初始化大小是11,扩容因子是0.75f,同HashMap,不同是初始化hashMap是10
public Hashtable() {
    this(11, 0.75f);
}
// Hashtable 不允许key和value值为null,如果为null,直接空指针
public synchronized V put(K key, V value) {
    // Make sure the value is not null
    if (value == null) {
        throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    Entry<?,?> tab[] = table;
    // key 为空直接空指针
    int hash = key.hashCode();
    // 计算该可以所在 数组中的位置
    // 0x7FFFFFFF 2的31次方-1
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    // 循环查找index 位置下的entry中的next 节点下是否与该key值相同。如果key值已经存在,则替换旧的值,并返回旧的值
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }
    // 如果没有key没有存在,则进行添加
    addEntry(hash, key, value, index);
    return null;
}
private void addEntry(int hash, K key, V value, int index) {
    modCount++;

    Entry<?,?> tab[] = table;
    // 如果当前存储的数据已经大于负载因子了,则进行rehash 扩容
    if (count >= threshold) {
        // Rehash the table if the threshold is exceeded
        rehash();

        tab = table;
        hash = key.hashCode();
        index = (hash & 0x7FFFFFFF) % tab.length;
    }

    // Creates the new entry.
    // 通过 key 应该存在table中的位置 index ,获得该位置中的entry
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>) tab[index];
    // 直接将该key的值作为 获得该index 位置的entry 的next节点
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
}
protected void rehash() {
    int oldCapacity = table.length;
    Entry<?,?>[] oldMap = table;

    // overflow-conscious code
    // 新的容器大小是原来大小的2倍 + 1
    int newCapacity = (oldCapacity << 1) + 1;
    if (newCapacity - MAX_ARRAY_SIZE > 0) {
        if (oldCapacity == MAX_ARRAY_SIZE)
            // Keep running with MAX_ARRAY_SIZE buckets
            return;
        newCapacity = MAX_ARRAY_SIZE;
    }
    Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

    modCount++;
    threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    table = newMap;

    for (int i = oldCapacity ; i-- > 0 ;) {
        for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
            Entry<K,V> e = old;
            old = old.next;

            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
            e.next = (Entry<K,V>)newMap[index];
            newMap[index] = e;
        }
    }
}
private static class Entry<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Entry<K,V> next;
}

Set

不可重复,HashSet 无序,LinkedHashMap、TreeSet 有序

HashSet 、LinkedHashSet 、TreeSet 实质上是维护了一个Map ,key是要存储的值,value 是一个 new Object();

HashSet

底部存储的是HashMap

public HashSet() {
    map = new HashMap<>();
}
public boolean add(E e) {
    //private static final Object PRESENT = new Object();
    return map.put(e, PRESENT)==null;
}

LinkedHashSet

底部存储的是LinkedHashMap

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

TreeSet

底部存储的是TreeMap

public TreeSet() {
    this(new TreeMap<E,Object>());
}
public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

Queue

ArrayBlockingQueue 参考 ArrayBlockingQueue 源码分析学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值