JAVA集合类

来源:互联网 发布:淘宝企业店铺提现 编辑:程序博客网 时间:2024/06/05 14:43

目前中文博客中充斥着很多很多介绍Java集合类的文章,但大多人云也云,一眼就让人理解的不多。这边尝试重新介绍下,希望可以抛砖引玉。


集合类的族谱关系

两种图片分别出自:
http://www.wilsonmar.com/1arrays.htm
http://beginnersbook.com/java-collections-tutorials/
本文中也有相当一部分参考上面两篇文章。

图1 Java 比较详尽的集合继承关系图



图2 Java集合类简单的继承图

继承关系图比较难记,但图2的简单,图2记住了,再辅助以下文分析,图1也就清楚了

集合类collection接口

集合类的List, Set, Queue都实现Collection接口,并所有集合类的常用操作都在Collection接口中。
接口的源码如下,通过名字,我们也可知道这些接口的动作到底是什么。
public interface Collection<E> extends Iterable<E> {    int size();    boolean isEmpty();    Iterator<E> iterator();    Object[] toArray();    <T> T[] toArray(T[] a);    boolean add(E e);    boolean remove(Object o);    boolean containsAll(Collection<?> c);    boolean addAll(Collection<? extends E> c);    boolean removeAll(Collection<?> c);    boolean retainAll(Collection<?> c);    void clear();    boolean equals(Object o);    int hashCode();}

vector类

比较老的一个类。可以从源码看出,内部使用数组实现,所有改动的操作都以synclyzed关键字,可见是线程安全的一个集合类。
public class Vector<E>    extends AbstractList<E>    implements List<E>, RandomAccess, Cloneable, java.io.Serializable{//内部使用数组作为vector的存储,既然是存储,删除,插入肯定是不方便的,当然随机访问肯定很方便    protected Object[] elementData;    //数组有效元素    protected int elementCount;    //数组满了的时候,每次扩容多少    protected int capacityIncrement;    //初始化vector,同时给定容量和每次增量    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 Vector(int initialCapacity) {        this(initialCapacity, 0);    }    //默认为10, 如果是大量使用的,必须一次给容量到位,不然每次都要重新申请拷贝    public Vector() {        this(10);    }    //复制    public Vector(Collection<? extends E> c) {        elementData = c.toArray();        elementCount = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);    }//剪掉,注意synchronized关键字,可知线程安全    public synchronized void trimToSize() {        modCount++;        int oldCapacity = elementData.length;        if (elementCount < oldCapacity) {            elementData = Arrays.copyOf(elementData, elementCount);        }    }   //扩容    public synchronized void ensureCapacity(int minCapacity) {        if (minCapacity > 0) {            modCount++;            ensureCapacityHelper(minCapacity);        }    }   //当前容量,synchronized    public synchronized int capacity() {        return elementData.length;    }//当前有效元素,存在的元素    public synchronized int size() {        return elementCount;    }//查找元素synchronized    public synchronized E elementAt(int index) {        if (index >= elementCount) {            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);        }        return elementData(index);    }    //改变元素,synchronized    public synchronized void setElementAt(E obj, int index) {        if (index >= elementCount) {            throw new ArrayIndexOutOfBoundsException(index + " >= " +                                                     elementCount);        }        elementData[index] = obj;    }   //删除元素,要大量拷贝。synchronized    public synchronized void removeElementAt(int index) {        modCount++;        if (index >= elementCount) {            throw new ArrayIndexOutOfBoundsException(index + " >= " +                                                     elementCount);        }        else if (index < 0) {            throw new ArrayIndexOutOfBoundsException(index);        }        int j = elementCount - index - 1;        if (j > 0) {            System.arraycopy(elementData, index + 1, elementData, index, j);        }        elementCount--;        elementData[elementCount] = null; /* to let gc do its work */    }    //增加元素,也要拷贝其他的,synchronized    public synchronized void insertElementAt(E obj, int index) {        modCount++;        if (index > elementCount) {            throw new ArrayIndexOutOfBoundsException(index                                                     + " > " + elementCount);        }        ensureCapacityHelper(elementCount + 1);        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);        elementData[index] = obj;        elementCount++;    }    //末尾增加元素,超过容量要重新复制,不然直接加就可以, 这也是初始容量比较重要的原因synchronized    public synchronized void addElement(E obj) {        modCount++;        ensureCapacityHelper(elementCount + 1);        elementData[elementCount++] = obj;    }        //转换为数组,synchronized    public synchronized Object[] toArray() {        return Arrays.copyOf(elementData, elementCount);    }   //获得指定位置元素,这个效率比较高synchronized    public synchronized E get(int index) {        if (index >= elementCount)            throw new ArrayIndexOutOfBoundsException(index);        return elementData(index);    }}

ArrayList 类

看到ArrayList类,就简直看到了Vector的双胞胎兄弟。但有些也不尽相同,比如ArrayList对内部数组的操作没有synchronized,效率为变高,但也是线程不安全版本。
ArrayList的扩容策略也不一样,vector是固定数量的扩容,而ArrayList是每次扩容为1.5倍。
public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{    //数组存储,相比于链表具有随机访问的优势,但删除和插入是劣势    private transient Object[] elementData;    //大小    private int size;    //构造函数,给定初始容量,为了提高效率,最好预估自己使用时候的容量    public ArrayList(int initialCapacity) {        super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        this.elementData = new Object[initialCapacity];    }    //构造函数,默认容量为10    public ArrayList() {        this(10);    }//扩容,1.5倍的扩容,不是扩容固定个数的元素    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);    }    //从其他集合类拷贝    public ArrayList(Collection<? extends E> c) {        elementData = c.toArray();        size = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, size, Object[].class);    }    //去指定位置上的元素,没有synchronized    public int indexOf(Object o) {        if (o == null) {            for (int i = 0; i < size; i++)                if (elementData[i]==null)                    return i;        } else {            for (int i = 0; i < size; i++)                if (o.equals(elementData[i]))                    return i;        }        return -1;    }//加一个元素    public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }    //指定位置加一个元素,要拷贝了    public void add(int index, E element) {        rangeCheckForAdd(index);        ensureCapacityInternal(size + 1);  // Increments modCount!!        System.arraycopy(elementData, index, elementData, index + 1,                         size - index);        elementData[index] = element;        size++;    }//删除元素    public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = elementData(index);        int numMoved = size - index - 1;        if (numMoved > 0)            System.arraycopy(elementData, index+1, elementData, index,                             numMoved);        elementData[--size] = null; // Let gc do its work        return oldValue;    }}

LinkedList 类

双向链表实现的线程不安全集合类。相比于ArrayList 和Vector,插入和删除操作比较快,但是随机访问就没有优势了。同时也不需要设置初始化容量。
public class LinkedList<E>    extends AbstractSequentialList<E>    implements List<E>, Deque<E>, Cloneable, java.io.Serializable{    //内部类,指针节点,双向链表结构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 int size = 0;//头节点    transient Node<E> first;//末尾节点    transient Node<E> last;    public LinkedList() {    }    //加其他集合    public LinkedList(Collection<? extends E> c) {        this();        addAll(c);    }    //private 函数,向表头加一个节点    private void linkFirst(E e) {        final Node<E> f = first;        final Node<E> newNode = new Node<>(null, e, f);        first = newNode;        if (f == null)            last = newNode;        else            f.prev = newNode;        size++;        modCount++;    }    //向表尾加节点,final的使用使得新创建节点引用不能改变指向    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++;    }//省略一些链表操作函数//获得第一个节点    public E getFirst() {        final Node<E> f = first;        if (f == null)            throw new NoSuchElementException();        return f.item;    }//获得最后一个节点    public E getLast() {        final Node<E> l = last;        if (l == null)            throw new NoSuchElementException();        return l.item;    }   //删除第一个节点    public E removeFirst() {        final Node<E> f = first;        if (f == null)            throw new NoSuchElementException();        return unlinkFirst(f);    }//删除最后一个节点    public E removeLast() {        final Node<E> l = last;        if (l == null)            throw new NoSuchElementException();        return unlinkLast(l);    }//在表头加节点    public void addFirst(E e) {        linkFirst(e);    }    //表末尾加节点    public void addLast(E e) {        linkLast(e);    }//在index处替换节点,而不是改变原有节点,因为已经final    public E set(int index, E element) {        checkElementIndex(index);        Node<E> x = node(index);        E oldVal = x.item;        x.item = element;        return oldVal;    }//省略其他}

Stack类

stack类比较简单,继承自Vector。是线程安全的集合类。
publicclass Stack<E> extends Vector<E> {        public Stack() {    }//push操作    public E push(E item) {        addElement(item);        return item;    }    //pop操作    public synchronized E pop() {        E       obj;        int     len = size();        obj = peek();        removeElementAt(len - 1);        return obj;    }    //peek操作    public synchronized E peek() {        int     len = size();        if (len == 0)            throw new EmptyStackException();        return elementAt(len - 1);    }}


PriorityQueue类

PriorityQueue为二叉堆的集合类实现,二叉堆的排序时间复杂度为O(logn), 对于大数据中取最小和最大几个元素效果比较好。
关于二叉堆的数据结构,请各位搜索之。

public class PriorityQueue<E> extends AbstractQueue<E>    implements java.io.Serializable {    private static final int DEFAULT_INITIAL_CAPACITY = 11;//存储二叉堆的数组    private transient Object[] queue;    private int size = 0;    //比较器    private final Comparator<? super E> comparator;    /**     * The number of times this priority queue has been     * <i>structurally modified</i>.  See AbstractList for gory details.     */    private transient int modCount = 0;    //构造函数    public PriorityQueue() {        this(DEFAULT_INITIAL_CAPACITY, null);    }    //带容量的构造函数    public PriorityQueue(int initialCapacity) {        this(initialCapacity, null);    }    //带容量和比较器的构造函数    public PriorityQueue(int initialCapacity,                         Comparator<? super E> comparator) {        // Note: This restriction of at least one is not actually needed,        // but continues for 1.5 compatibility        if (initialCapacity < 1)            throw new IllegalArgumentException();        this.queue = new Object[initialCapacity];        this.comparator = comparator;    }    //从其他集合拷贝的构造函数    @SuppressWarnings("unchecked")    public PriorityQueue(Collection<? extends E> c) {        if (c instanceof SortedSet<?>) {            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;            this.comparator = (Comparator<? super E>) ss.comparator();            initElementsFromCollection(ss);        }        else if (c instanceof PriorityQueue<?>) {            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;            this.comparator = (Comparator<? super E>) pq.comparator();            initFromPriorityQueue(pq);        }        else {            this.comparator = null;            initFromCollection(c);        }    }//private函数, 直接从其他PriorityQueue拷贝,直接拷贝数组和大小    private void initFromPriorityQueue(PriorityQueue<? extends E> c) {        if (c.getClass() == PriorityQueue.class) {            this.queue = c.toArray();            this.size = c.size();        } else {            initFromCollection(c);        }    }//从collection中初始化元素,检查不准元素为Null    private void initElementsFromCollection(Collection<? extends E> c) {        Object[] a = c.toArray();        // If c.toArray incorrectly doesn't return Object[], copy it.        if (a.getClass() != Object[].class)            a = Arrays.copyOf(a, a.length, Object[].class);        int len = a.length;        if (len == 1 || this.comparator != null)            for (int i = 0; i < len; i++)                if (a[i] == null)                    throw new NullPointerException();        this.queue = a;        this.size = a.length;    }    //增加容量,加一倍或一点五倍,64为界    private void grow(int minCapacity) {        int oldCapacity = queue.length;        // Double size if small; else grow by 50%        int newCapacity = oldCapacity + ((oldCapacity < 64) ?                                         (oldCapacity + 2) :                                         (oldCapacity >> 1));        // overflow-conscious code        if (newCapacity - MAX_ARRAY_SIZE > 0)            newCapacity = hugeCapacity(minCapacity);        queue = Arrays.copyOf(queue, newCapacity);    }//删除元素    private E removeAt(int i) {        assert i >= 0 && i < size;        modCount++;        int s = --size;        if (s == i) // removed last element            queue[i] = null;        else {            E moved = (E) queue[s];            queue[s] = null;            siftDown(i, moved);            if (queue[i] == moved) {                siftUp(i, moved);                if (queue[i] != moved)                    return moved;            }        }        return null;    }    //下面几个函数为二叉堆的上移下移操作,利用堆的q[n]的左右孩子为q[2n+2]和q[2n+1]的属性    private void siftUp(int k, E x) {        if (comparator != null)            siftUpUsingComparator(k, x);        else            siftUpComparable(k, x);    }    private void siftUpComparable(int k, E x) {        Comparable<? super E> key = (Comparable<? super E>) x;        while (k > 0) {            int parent = (k - 1) >>> 1;            Object e = queue[parent];            if (key.compareTo((E) e) >= 0)                break;            queue[k] = e;            k = parent;        }        queue[k] = key;    }    private void siftUpUsingComparator(int k, E x) {        while (k > 0) {            int parent = (k - 1) >>> 1;            Object e = queue[parent];            if (comparator.compare(x, (E) e) >= 0)                break;            queue[k] = e;            k = parent;        }        queue[k] = x;    }    /**     * Inserts item x at position k, maintaining heap invariant by     * demoting x down the tree repeatedly until it is less than or     * equal to its children or is a leaf.     *     * @param k the position to fill     * @param x the item to insert     */    private void siftDown(int k, E x) {        if (comparator != null)            siftDownUsingComparator(k, x);        else            siftDownComparable(k, x);    }    private void siftDownComparable(int k, E x) {        Comparable<? super E> key = (Comparable<? super E>)x;        int half = size >>> 1;        // loop while a non-leaf        while (k < half) {            int child = (k << 1) + 1; // assume left child is least            Object c = queue[child];            int right = child + 1;            if (right < size &&                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)                c = queue[child = right];            if (key.compareTo((E) c) <= 0)                break;            queue[k] = c;            k = child;        }        queue[k] = key;    }    private void siftDownUsingComparator(int k, E x) {        int half = size >>> 1;        while (k < half) {            int child = (k << 1) + 1;            Object c = queue[child];            int right = child + 1;            if (right < size &&                comparator.compare((E) c, (E) queue[right]) > 0)                c = queue[child = right];            if (comparator.compare(x, (E) c) <= 0)                break;            queue[k] = c;            k = child;        }        queue[k] = x;    }    //堆化操作    private void heapify() {        for (int i = (size >>> 1) - 1; i >= 0; i--)            siftDown(i, (E) queue[i]);    }}


HashMap类

Hashmap类也是线程不安全的集合类,内部用数组作为存储。使用的时候需要注意,当元素快满,并且接近threshold的时候,会重新Hash,并且造成整个数组的拷贝。
public class HashMap<K,V>    extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable{    //默认的容量,一定要2的倍数    static final int DEFAULT_INITIAL_CAPACITY = 16;    //最大数量不超过2的32次方    static final int MAXIMUM_CAPACITY = 1 << 30;    //重hash因子,比方说容量为64,到48的时候就重新hash排列    static final float DEFAULT_LOAD_FACTOR = 0.75f;    //存储的key value 数组    transient Entry<K,V>[] table;    //存储元素的多少    transient int size;    //下一次调整大小的数值(capacity * load factor).     * @serial     *    int threshold;//调整因子    final float loadFactor;    //hash种子    transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);    //构造函数,容量要为2的倍数    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);        //一直找到大于参数的第一个2的倍数        int capacity = 1;        while (capacity < initialCapacity)            capacity <<= 1;        this.loadFactor = loadFactor;        threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);        table = new Entry[capacity];        useAltHashing = sun.misc.VM.isBooted() &&                (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);        init();    }//计算hash码,为什么这么算?学数学的来解释下,不懂    final int hash(Object k) {        int h = 0;        if (useAltHashing) {            if (k instanceof String) {                return sun.misc.Hashing.stringHash32((String) k);            }            h = hashSeed;        }        h ^= k.hashCode();        // This function ensures that hashCodes that differ only by        // constant multiples at each bit position have a bounded        // number of collisions (approximately 8 at default load factor).        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }    /**     * Returns the number of key-value mappings in this map.     *     * @return the number of key-value mappings in this map     */    public int size() {        return size;    }//真的null做单独处理,说明可以放null的键值    public V get(Object key) {        if (key == null)            return getForNullKey();        Entry<K,V> entry = getEntry(key);        return null == entry ? null : entry.getValue();    }    private V getForNullKey() {        for (Entry<K,V> e = table[0]; e != null; e = e.next) {            if (e.key == null)                return e.value;        }        return null;    }//get 元素    final Entry<K,V> getEntry(Object key) {        int hash = (key == null) ? 0 : hash(key);        for (Entry<K,V> e = table[indexFor(hash, table.length)];             e != null;             e = e.next) {            Object k;            if (e.hash == hash &&                ((k = e.key) == key || (key != null && key.equals(k))))                return e;        }        return null;    }//插入元素,null键默认放在table[0]    public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key);        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }    private V putForNullKey(V value) {        for (Entry<K,V> e = table[0]; e != null; e = e.next) {            if (e.key == null) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(0, null, value, 0);        return null;    }    //当超过threshold的时候需要重新hash,因为Index和数组长度有关,这个对效率是致命的    void resize(int newCapacity) {        Entry[] oldTable = table;        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return;        }        Entry[] newTable = new Entry[newCapacity];        boolean oldAltHashing = useAltHashing;        useAltHashing |= sun.misc.VM.isBooted() &&                (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);        boolean rehash = oldAltHashing ^ useAltHashing;        transfer(newTable, rehash);        table = newTable;        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);    }    //重新hash    void transfer(Entry[] newTable, boolean rehash) {        int newCapacity = newTable.length;        for (Entry<K,V> e : table) {            while(null != e) {                Entry<K,V> next = e.next;                if (rehash) {                    e.hash = null == e.key ? 0 : hash(e.key);                }                int i = indexFor(e.hash, newCapacity);                e.next = newTable[i];                newTable[i] = e;                e = next;            }        }    }//删除key    public V remove(Object key) {        Entry<K,V> e = removeEntryForKey(key);        return (e == null ? null : e.value);    }}

HashTable类

几乎和HashMap是双胞胎兄弟,但是HashTable是线程安全的,并且不接受null的key.并且实现自比较老的Dictionary,而不是Map.
public class Hashtable<K,V>    extends Dictionary<K,V>    implements Map<K,V>, Cloneable, java.io.Serializable {    private transient Entry<K,V>[] table;//数组中的元素    private transient int count;    //下次重新Hash的大小    private int threshold;    //重载因子    private float loadFactor;//种子    transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);//hash函数    private int hash(Object k) {        if (useAltHashing) {            if (k.getClass() == String.class) {                return sun.misc.Hashing.stringHash32((String) k);            } else {                int h = hashSeed ^ k.hashCode();                // This function ensures that hashCodes that differ only by                // constant multiples at each bit position have a bounded                // number of collisions (approximately 8 at default load factor).                h ^= (h >>> 20) ^ (h >>> 12);                return h ^ (h >>> 7) ^ (h >>> 4);             }        } else  {            return k.hashCode();        }    }//函数为synchronized    public synchronized boolean contains(Object value) {        if (value == null) {            throw new NullPointerException();        }        Entry tab[] = table;        for (int i = tab.length ; i-- > 0 ;) {            for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {                if (e.value.equals(value)) {                    return true;                }            }        }        return false;    }//get函数    public synchronized V get(Object key) {        Entry tab[] = table;        int hash = hash(key);        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                return e.value;            }        }        return null;    }//重新hash函数    protected void rehash() {        int oldCapacity = table.length;        Entry<K,V>[] oldMap = table;        // overflow-conscious code        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<K,V>[] newMap = new Entry[newCapacity];        modCount++;        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);        boolean currentAltHashing = useAltHashing;        useAltHashing = sun.misc.VM.isBooted() &&                (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);        boolean rehash = currentAltHashing ^ useAltHashing;        table = newMap;        for (int i = oldCapacity ; i-- > 0 ;) {            for (Entry<K,V> old = oldMap[i] ; old != null ; ) {                Entry<K,V> e = old;                old = old.next;                if (rehash) {                    e.hash = hash(e.key);                }                int index = (e.hash & 0x7FFFFFFF) % newCapacity;                e.next = newMap[index];                newMap[index] = e;            }        }    }    //put函数synchronized    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;        int hash = hash(key);        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                V old = e.value;                e.value = value;                return old;            }        }        modCount++;        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            rehash();            tab = table;            hash = hash(key);            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        Entry<K,V> e = tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;        return null;    }//remove函数    public synchronized V remove(Object key) {        Entry tab[] = table;        int hash = hash(key);        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                modCount++;                if (prev != null) {                    prev.next = e.next;                } else {                    tab[index] = e.next;                }                count--;                V oldValue = e.value;                e.value = null;                return oldValue;            }        }        return null;    }}

LinkedHashMap

LinkedHashMap 和HashMap 几乎一样,唯一的区别是,LinkedHashMap可以有序的访问。 既然是hash后放在数组中,那理论上数组肯定是无序的,那为什么可以有序访问呢?原因是LinkedHashMap改造了HashMap的元素,放入指针,用循环链表的方式连起来了。

public class LinkedHashMap<K,V>    extends HashMap<K,V>    implements Map<K,V>{    //放在链表中的头节点    private transient Entry<K,V> header;    //true的时候,访问完一个元素,就放到最后,否则就严格按照插入时候的顺序    private final boolean accessOrder;//初始化容量和重构因子    public LinkedHashMap(int initialCapacity, float loadFactor) {        super(initialCapacity, loadFactor);        accessOrder = false;    }    //复制构造函数    public LinkedHashMap(Map<? extends K, ? extends V> m) {        super(m);        accessOrder = false;    }    //可设置访问顺序的构造函数    public LinkedHashMap(int initialCapacity,                         float loadFactor,                         boolean accessOrder) {        super(initialCapacity, loadFactor);        this.accessOrder = accessOrder;    }    //复制到其他hashmap,使用已有的顺序来    @Override    void transfer(HashMap.Entry[] newTable, boolean rehash) {        int newCapacity = newTable.length;        for (Entry<K,V> e = header.after; e != header; e = e.after) {            if (rehash)                e.hash = (e.key == null) ? 0 : hash(e.key);            int index = indexFor(e.hash, newCapacity);            e.next = newTable[index];            newTable[index] = e;        }    }//get的时候,在recordAccess中把get的节点放在最后    public V get(Object key) {        Entry<K,V> e = (Entry<K,V>)getEntry(key);        if (e == null)            return null;        e.recordAccess(this);        return e.value;    }    private static class Entry<K,V> extends HashMap.Entry<K,V> {        //加入指针        Entry<K,V> before, after;        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {            super(hash, key, value, next);        }        private void addBefore(Entry<K,V> existingEntry) {            after  = existingEntry;            before = existingEntry.before;            before.after = this;            after.before = this;        }        void recordAccess(HashMap<K,V> m) {            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;            if (lm.accessOrder) {                lm.modCount++;                remove();                addBefore(lm.header);            }          }}


TreeMap 实现类

TreeMap使用二叉搜索树作为存储,确切地说应该是一个红黑树的结构。对应搜索性质的数据组合帮助较大。
public class TreeMap<K,V>    extends AbstractMap<K,V>    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{    //比较器,要使用其compare方法    private final Comparator<? super K> comparator;//树的root节点    private transient Entry<K,V> root = null;//节点数量    private transient int size = 0;//默认比较器为空    public TreeMap() {        comparator = null;    }//带比较器版本    public TreeMap(Comparator<? super K> comparator) {        this.comparator = comparator;    }    //复制    public TreeMap(Map<? extends K, ? extends V> m) {        comparator = null;        putAll(m);    }    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) {        }    }//根据搜索树的性质查找对应键值    final Entry<K,V> getEntry(Object key) {        // Offload comparator-based version for sake of performance        if (comparator != null)            return getEntryUsingComparator(key);        if (key == null)            throw new NullPointerException();        Comparable<? super K> k = (Comparable<? super K>) key;        Entry<K,V> p = root;        while (p != null) {            int cmp = k.compareTo(p.key);            if (cmp < 0)                p = p.left;            else if (cmp > 0)                p = p.right;            else                return p;        }        return 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();            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;    }              // Red-black mechanics    private static final boolean RED   = false;    private static final boolean BLACK = true;    //红黑树的节点    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;        boolean color = BLACK;        /**         * Make a new cell with given key, value, and parent, and with         * {@code null} child links, and BLACK color.         */        Entry(K key, V value, Entry<K,V> parent) {            this.key = key;            this.value = value;            this.parent = parent;        }        /**         * Returns the key.         *         * @return the key         */        public K getKey() {            return key;        }        /**         * Returns the value associated with the key.         *         * @return the value associated with the key         */        public V getValue() {            return value;        }        /**         * Replaces the value currently associated with the key with the given         * value.         *         * @return the value associated with the key before this method was         *         called         */        public V setValue(V value) {            V oldValue = this.value;            this.value = value;            return oldValue;        }        public boolean equals(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry<?,?> e = (Map.Entry<?,?>)o;            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());        }        public int hashCode() {            int keyHash = (key==null ? 0 : key.hashCode());            int valueHash = (value==null ? 0 : value.hashCode());            return keyHash ^ valueHash;        }        public String toString() {            return key + "=" + value;        }    }}

Set类 HashSet ,LinkedHashSet,TreeSet

这三个类全部依赖于对应的Map来实现,看懂了Map, Set也就不再话下。利用的算法和组织结构一样,这边不展开说明。



小结

这边主要集合源码,来分析各种集合类的实现。重要的是算法和数据结构。理解这些就理解一切。

 



0 0
原创粉丝点击