解析JAVA集合

List

  • ArrayList:
    • 使用数组实现,查询快,增删慢,非线程安全
    • 默认长度是0,添加元素时判断如果是初始共享数组,则扩容长度10,固定1.5倍扩容
    • 按插入顺序排序,可重复元素
/* 添加元素时如果是共享实例数组则扩容长度为10 */
private static final int DEFAULT_CAPACITY = 10;

/* 与下面一样,区分的目的在于了解第一次数组添加元素时数组的扩容状况 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/* 用于共享空实例数组,防止多次创建空数组浪费系统资源 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/* ArrayList使用该数组存储数据 */
transient Object[] elementData;

/* 创建并赋值空数组 */
public ArrayList() {
    /* 注意:当前是空数组,默认长度是0 */
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

public boolean add(E e) {
    /* 判断长度,根据条件扩容 */
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    /* 判断当前如果添加元素,数组是否超出,如果超出进行扩容 */
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    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);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
  • LinkedList:
    • 使用双向链表(Node<E>)实现,查询慢,增删快,非线程安全
transient Node<E> first;
transient Node<E> last;

public boolean add(E e) {
    linkLast(e);
    return true;
}

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++;
}

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;
    
    /* 省略 */
}
  • Vector:
    • 使用数组实现,查询快,增删慢,使用了synchronized对象锁,线程安全
    • 默认长度为10,扩容时如果扩容量大于0当前长度加扩容量,否则扩容量加扩容量
    • 按插入顺序排序,可重复元素
/* 使用数组存储数据 */
protected Object[] elementData;

/* 容器扩容时增长量 */
protected int capacityIncrement;

public Vector() {
    this(10);
}
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}
private void ensureCapacityHelper(int minCapacity) {
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    
    /* 根据增长量设置扩容,默认增长量0,每次扩容时容量翻倍 */
    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);
}

Map

  • HashMap:
    • 使用单向链表(Node<K,V>)数组实现,非线程安全
    • 数组长度默认16,链表长度超出8会转换成红黑树
    • 最多仅允许一条Key为null,"null"可以和null同时存在
    • 根据Key的哈希值确定当前元素存储到的数组位置,以数组排序
/* 无参构造器创建容器首次添加元素会自动初始化容器为2的4次幂 16 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

/* 有参构造器创建容器参数大于该值则替换 */
static final int MAXIMUM_CAPACITY = 1 << 30;

/* 默认负载因子,当存储量超出负载因子时进行扩容 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/* 链表阈值,数组节点的链表节点超出该值会转换为红黑树 */
static final int TREEIFY_THRESHOLD = 8;

/* 数据容器 */
transient Node<K,V>[] table;

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                    treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

/* 单向链表节点 */
static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

    /* 省略  */
}

/* 红黑树节点 */
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    TreeNode<K,V> parent;  // red-black tree links
    TreeNode<K,V> left;
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    boolean red;

    /* 省略 */
}
  • LinkedHashMap:
    • 使用双向链表(Entry<K,V>)数组实现,非线程安全
    • 为有序(添加顺序排序)且不可重复
    • 继承自HashMap并重写了newNode方法,在创建节点时返回双向链表节点
    • 因为继承自HashMap所以数组容器长度默认为16,Key值可以为null
/* 双向链表首节点 */
transient LinkedHashMap.Entry<K,V> head;

/* 双向链表尾节点 */
transient LinkedHashMap.Entry<K,V> tail;

/* 访问顺序为true,对于插入顺序为false */
final boolean accessOrder;


public LinkedHashMap() {
    super();
    accessOrder = false;
}

/* 重写HashMap的newNode方法,返回双向链表节点 */
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    linkNodeLast(p);
    return p;
}

static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}
  • TreeMap:
    • 使用红黑树(Entry<K,V>节点)实现,非线程安全
    • 可以对添加进来的元素进行自动排序,默认使用自然顺序排序
    • Key值不能是null,否则会报空指针异常
/* 比较器用于维护树映射中的顺序,如果使用键的自然顺序则为null,默认null */
private final Comparator<? super K> comparator;

/* 红黑树根节点 */
private transient Entry<K,V> root;

public TreeMap() {
    comparator = null;
}

public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
        Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

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;
    boolean color = BLACK;

    /* 省略 */
}
  • HashTable:
    • 使用单向链表(Entry<K,V>)数组实现,使用了synchronized对象锁,线程安全
    • 容器大小默认11,负载因子0.75,数组扩容时直接翻倍加一,第一次扩容变为23
    • Key值不能是null,否则会报空指针异常
/* 单向链表数组 */
private transient Entry<?,?>[] table;

public Hashtable() {
    this(11, 0.75f);
}

public Hashtable(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal Load: "+loadFactor);

    if (initialCapacity==0)
        initialCapacity = 1;
    this.loadFactor = loadFactor;
    table = new Entry<?,?>[initialCapacity];
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}

public synchronized V put(K key, V value) {
    if (value == null) {
        throw new NullPointerException();
    }

    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    @SuppressWarnings("unchecked")
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            V old = entry.value;
            entry.value = value;
            return old;
        }
    }

    addEntry(hash, key, value, index);
    return null;
}

private void addEntry(int hash, K key, V value, int index) {
    modCount++;
    Entry<?,?> tab[] = table;
    if (count >= threshold) {
        rehash();
        tab = table;
        hash = key.hashCode();
        index = (hash & 0x7FFFFFFF) % tab.length;
    }
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>) tab[index];
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
}

private static class Entry<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Entry<K,V> next;

    /* 省略 */
}
  • ConcurrentHashMap:
    • 使用单向链表数组实现,使用了synchronized代码块锁,锁住的是数组节点中的单向链表,效率更高,线程安全
    • 默认初始容量16,负载因子0.75,链表阈值8超出阈值转换成红黑树
private static final int MAXIMUM_CAPACITY = 1 << 30;
private static final int DEFAULT_CAPACITY = 16;
private static final float LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;

transient volatile Node<K,V>[] table;
private transient volatile Node<K,V>[] nextTable;

Set

  • HashSet:底层以HashMap的Key值实现数据存储,所有对应Value都是new Object(),有序(Key值的Hash值排序)不可重复集,非线程安全
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}
  • LinkedHashSet:底层以LinkedHashMap的Key值实现数据存储,所有对应Value都是new Object(),有序(添加顺序排序)不可重复集,非线程安全
public LinkedHashSet() {
    super(16, .75f, true);
}


HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
  • TreeSet:底层默认以TreeMap的Key值实现数据存储,所有对应Value都是new Object(),可以对添加进来的元素进行排序,非线程安全
private transient NavigableMap<E,Object> m;
private static final Object PRESENT = new Object();

public TreeSet() {
    this(new TreeMap<E,Object>());
}
TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

Collection:是List和Set集合的父类,是一个集合接口,提供了对集合对象进行基本操作的通用方法

Collections是一个工具类,不能被实例化,提供了很多集合功能

Comparable :内比较器,使用compareTo(T o)方法对当前类与参数进行比较

Comparator:外比较器,使用compare(T o1, T o2)方法对传入的参数进行比较

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值