java集合学习

简单了解java中的集合底层的存储结构。能力有限,如果有什么不对的地方希望大家指出,不胜感激
单向链表
这里写图片描述
单向链表可以很容易实现一个栈,详情请点击链接

双向链表
这里写图片描述

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;
    transient Node<E> first;
    transient Node<E> last;
    Node<E> node(int index) {
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }
  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++;
    }
    //删除元素,先遍历集合找到对应的node然后调用这个方法
    E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
        x.item = null;
        size--;
        modCount++;
        return element;
    }
}

数组结构

java.util.Vector

public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //底层是数组结构
    protected Object[] elementData;
    //元素数量
    protected int elementCount;
    //数组的扩展数量(如果有指定那么每次按指定数量扩展数组,如果没有指定,那么数组直接扩展为原数组2倍)
    protected int capacityIncrement;
    // 新增元素的时候,会判断当前数组是否可以存下这个对象,如果存不下就扩展
    // 如果指定扩展数量就扩展固定数量否则,直接将原数组扩大一倍
    //希望扩展的最小数量 minCapacity
    private void grow(int minCapacity) {
        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);
    }
    // 删除元素
    public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);
        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
        //将elementData[index+1]开始后面所有的元素 复制到elementData[index]开始
        //删除元素不改变数组大小
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--elementCount] = null; 
        return oldValue;
    }
 }

java.util.ArrayList

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{   //默认初始数组大小 10
    private static final int DEFAULT_CAPACITY = 10;
    //底层是数组结构
    transient Object[] elementData;
    private int size;//元素个数
    //当数组存不下要保存的所有元素的时候增长 50%
    //最小数量 minCapacity
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        // 增长原长度的50%
        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);
    }
    // 从头开始删除找到的第一个元素
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
        //将elementData[index+1]开始后面所有的元素 复制到elementData[index]开始
        //删除元素不改变数组大小
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
}

Set

java.util.HashSet 由java.util.HashMap实现

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
{
    private transient HashMap<E,Object> map;
    // value值
    private static final Object PRESENT = new Object();
}

java.util.TreeSet 由 java.util.TreeMap 实现

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    private transient NavigableMap<E,Object> m;
    // value值
    private static final Object PRESENT = new Object();
}

Map

java.util.HashMap

这里写图片描述

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    transient Node<K,V>[] table;// 底层是数组加链表结构,每个数组上的元素都是链表的开始
    transient Set<Map.Entry<K,V>> entrySet;// 是内部类EntrySet,具体方法依赖于HashMap自己
    transient int size;//元素个数
    //如果有指定容量大小,那么该值是通过java.util.HashMap#tableSizeFor方法计算阀值,并以此阀值作为初始数组的大小 值只能是 16*2^n;
    //如果是使用默认的那么该值是java.util.HashMap#resize来赋值=(初始用量*加载因子)
    //当元素个数大于阀值的时候数组就扩展一倍,阀值一样扩大一倍resize方法进行修改
    int threshold;//阀值 最大是 Integer.MAX_VALUE
    final float loadFactor;// 加载因子,用来计算阀值 
    final Node<K,V>[] resize(){
        if (oldCap > 0) {
            //oldCap原数组大小,如大于0,就是已经初始化了过了
            if (oldCap >= MAXIMUM_CAPACITY) { //如果已经大于了最大容量 1 << 30
                threshold = Integer.MAX_VALUE;//直接设置阀值为最大整数
                return oldTab;
                //否则的话原大小扩容至2倍,原阀值也扩容至2倍
            } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        } else if (oldThr > 0) // 初始容量等于原阀值
        //如果指定了初始容量和加载因子,会先计算阀值(16*2^n),初始化数组的时候走到这一步,新数组=阀值的容量
            newCap = oldThr;
        else { // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
          //如指定了初始容量和加载因子,初始化会走这里,新的阀值等于新的 数组长度*加载因子
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
    //创建一个新的数组长度为newCap,并将原来的数据(如果原数组有值的话)填入到新的数组,位置是根据hash重新计算的。所以有可能会变。这就是为什么不保证顺序
    }
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        //存值之前先判断数组,如果数组为空就调用resize()进行初始化
        //(数组长度-1)&hash就是新元素的数组下标,如果该位置没有值就存在这个位置
        //如果值就和这个元素开始的链表进行判断看是否相等(依赖equals方法),key相等的更新value
        // key不相等的就创建新的Node,用该链表的最后一个节点的next指向新创建的节点
        //最后判断元素数量和阀值比较
        if (++size > threshold)
            resize();
    }
    // 单向链表,HashMap中保存的元素,如果有hash值相同,就保存下一个元素的引用
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
    }
    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public final int size()                 { return size; }
        public final void clear()               { HashMap.this.clear(); }
        public final Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator();
        }
    }
    // 迭代器的具体实现,依赖HashMap.HashIterator,最后是调用HashMap.table[]中直接拿Node
    final class EntryIterator extends HashIterator
        implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }
    abstract class HashIterator {
        Node<K,V> next;        // next entry to return
        Node<K,V> current;     // current entry
        int expectedModCount;  // for fast-fail
        int index;             // current slot

        HashIterator() {
            expectedModCount = modCount;
            Node<K,V>[] t = table;
            current = next = null;
            index = 0;
            // 找到数组中第一个节点,让next指向这个值
            if (t != null && size > 0) { 
                do {} while (index < t.length && (next = t[index++]) == null);
            }
        }
        public final boolean hasNext() {
            return next != null;
        }
        //返回当前值并让next指向下一个节点
        final Node<K,V> nextNode() {
            Node<K,V>[] t;
            Node<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            //如果当前节点有下一个节点的引用,就让next指向下一个节点
            if ((next = (current = e).next) == null && (t = table) != null) {
                //如果当前节点没有下一个节点的引用,就从保存的index开始往后找数组中的第一个节点
                do {} while (index < t.length && (next = t[index++]) == null);
            }
            return e;
        }
    }
}

java.util.LinkedHashMap

继承与HashMap重写了newNode();
在HashMap的基础上每个节点增加了前后元素的引用,形成了一个双向链表,以此保证顺序;
节点使用静态内部类java.util.LinkedHashMap.Entry继承自的HashMap.Node,保存上一个下一个元素
存取有序依赖链表结构
这里写图片描述

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
{
    transient LinkedHashMap.Entry<K,V> head;
    transient LinkedHashMap.Entry<K,V> tail;
    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;
    }
    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
    }
}

java.util.TreeMap

树形结构,不是特别了解,画的不对的地方希望指出。
这里写图片描述

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
    private final Comparator<? super K> comparator;//比较器
    private transient Entry<K,V> root = 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;
        // 根节点不为空需要进行比较
        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);//节点相等会更新value,并返回原value
            //一直找到t==null
            } 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);
        }
        //如果没有找到相等的key,那么已最后一个不为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;
    }
    //遍历依赖的方法先找到第一个元素getFirstEntry(),再依次找下一个元素方向 左中右
    //找到左边第一个元素
    final Entry<K,V> getFirstEntry() {
        Entry<K,V> p = root;
        if (p != null)
            while (p.left != null)
                p = p.left;
        return p;
    }
    //根据传入的节点找到下一个节点
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
        if (t == null)
            return null;
        else if (t.right != null) {
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
        } else {
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) {
                ch = p;
                p = p.parent;
            }
            return p;
        }
    }
    //元素类型
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;
        V value;
        Entry<K,V> left = null;//左叶子节点
        Entry<K,V> right = null;//右叶子节点
        Entry<K,V> parent;//父节点
    }  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值