首页 > 代码库 > HashMap,LinkedHashMap和Hashtable类的深入剖析与理解

HashMap,LinkedHashMap和Hashtable类的深入剖析与理解

上一篇文章写了一些关于HashMap以及HashMap的线程安全问题,这篇文章再来说说Map系列中HashMap,LinkedHashMap和Hashtable三者之间的差异以及该注意的地方。

HashMap的该注意的地方就不赘述了,上一篇已经描述过了。

一,LinkedHashMap的知识点


从类名上理解,这个类是个链表HashMap,这个类继承了HashMap,重写了父类的一些方法。关于LinkedHashMap,有以下注意的地方:

  1. LinkedHashMap的初始默认容量为16,载入因子为0.75(继承与HashMap)

  2. LinkedHashMap不支持线程安全

  3. LinkedHashMap允许key和value为null

  4. LinkedHashMap是个双链表,遵循先进先出原则

二,Hashtable的知识点


这个类继承了Dictionary类,并且也实现了Map和Cloneable,Serializable接口,也就是说,这个类可以被克隆,也可以被序列化,这个类有以下注意的地方:

  1. Hashtable的初始默认容量为16,载入因子为0.75

  2. Hashtable是线程安全的

  3. Hashtable不允许key或者value为null

  4. Hashtable的操作使用了synchronized来达到线程安全问题,连entrySet()方法中也用了Collections.synchronizedSet(),但是还是避免不了Iterator的快速失败,因此,在有迭代器操作时,一定要注意。


三,HashMap和LinkedHashMap的关键点


其实LinkedHashMap的关键功能就是为了保证插入的数据的顺序问题。由于LinkedHashMap是双链表结构,那这样导致每次插入的数据都是由指针顺序指向的,因此取数据时,也就是顺序取了,如果你的结合大多数情况下,在copy时还要保证顺序不变,那么LInkedHashMap是个很好的选择;而HashMap由于是通过hash来存储在Hash表中的值来查找数据的,而hash值又是随机的,这样导致存入的数据顺序和取出来的数据顺序是不同的,下面分别是LinkedHashMap和HashMap的取数据的源码,一看便知:

private abstract class LinkedHashIterator<T> implements Iterator<T> {
	Entry<K,V> nextEntry    = header.after;
	Entry<K,V> lastReturned = null;

	/**
	 * The modCount value that the iterator believes that the backing
	 * List should have.  If this expectation is violated, the iterator
	 * has detected concurrent modification.
	 */
	int expectedModCount = modCount;

	public boolean hasNext() {
            return nextEntry != header;
	}

	public void remove() {
	    if (lastReturned == null)
		throw new IllegalStateException();
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();

            LinkedHashMap.this.remove(lastReturned.key);
            lastReturned = null;
            expectedModCount = modCount;
	}
        //注意点就在这里e.after
	Entry<K,V> nextEntry() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
            if (nextEntry == header)
                throw new NoSuchElementException();

            Entry<K,V> e = lastReturned = nextEntry;
            nextEntry = e.after;
            return e;
	}
    }

HashMap:

private abstract class HashIterator<E> implements Iterator<E> {
        Entry<K,V> next;	// next entry to return
        int expectedModCount;	// For fast-fail
        int index;		// current slot
        Entry<K,V> current;	// current entry

        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
        }

        public final boolean hasNext() {
            return next != null;
        }
        //可以看到,HashMap的取值是从hash表中通过表索引取的,而这个hash表的数据顺序已经在put的时候存储好了
        final Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();

            if ((next = e.next) == null) {
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null)
                    ;
            }
	    current = e;
            return e;
        }
        
        public void remove() {
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }

    }