集合框架map学习笔记一LinkedHashMap

Map: 

1、HashMap 

2、LinkedHashMap 

3、IdentityHashMap 

4、WeakHashMap 

5、TreeMap 

6、EnumMap 

7、ConcurrentHashMap 

8、ConcurrentSkipListMap 

今天主要学习的是LinkedHashMap。


1、LinkedHashMap

LinkedHashMap是继承HashMap的一个子类,所有存储的结构也是Entry[],同样是以key的hashCode值来计算key-value所在的Entry[]桶所在的下标。来实现快速的存放和查询。但是LinkedHashMap除了继承父类HashMap的功能以外,解决了HashMap无序的问题。

LinkedHashMap遍历元素的时候,遍历的顺序是以数据的存入的顺序。


2、LinkedHashMap的数据存放

因为LinkedHashMap在HashMap的Entry[]对象中,继承Entry对象扩充了自己的Entry对象能力,增加了before和after属性,使得数据存入以后,成为一个双向链表的形式。因为双向链表的处理,所以LinkedHashMap的数据写入性能没有HashMap高。

LinkedHashMap的数据写入也是调用父类的put方法(已经在HashMap里面介绍了put方法了),而重写了addEntry方法。对于Entry对象的处理,主要在于建立双向链表,使得由header对象开始,与每次加入的对象成为双向链表。


/**
     * This override alters behavior of superclass put method. It causes newly
     * allocated entry to get inserted at the end of the linked list and
     * removes the eldest entry if appropriate.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        createEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed, else grow capacity if appropriate
        Entry eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        } else {
            if (size >= threshold)
                resize(2 * table.length);
        }
    }
void createEntry(int hash, K key, V value, int bucketIndex) {
        HashMap.Entry old = table[bucketIndex];
	Entry e = new Entry(hash, key, value, old);
        table[bucketIndex] = e;
        e.addBefore(header);
        size++;
    }
/**
         * Inserts this entry before the specified existing entry in the list.
         */
        private void addBefore(Entry existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }

2、LinkedHashMap的数据获取

LinkedHashMap的get方法其实和HashMap的get方法实现是一致的,但是HashMap的get方法,在null值的判断上处理了两次,一次是get方法中,一次在底层调用getEntry方法的时候也判断了一次,而LinkedHashMap对这里进行了优化,只在getEntry中去判断就可以了。

LinkedHashMap中key值为null的情况,仍然和HashMap一样放在Entry[0]中,也就是桶的首位。

特别之处在于accessOrder为true的情况,后面再讲。

3、LinkedHashMap的数据遍历

LinkedHashMap也是一般通过keySet方法进行key值的遍历。而LinkedHashMap的迭代器并不是像HashMap一样先遍历桶(Entry[])的,而是由header元素开始慢慢的next读取after对象。所以读取的顺序和写入的顺序一致。

private abstract class LinkedHashIterator implements Iterator {
	Entry nextEntry    = header.after;
	Entry 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;
	}

	Entry nextEntry() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
            if (nextEntry == header)
                throw new NoSuchElementException();

            Entry e = lastReturned = nextEntry;
            nextEntry = e.after;
            return e;
	}
    }

3、LinkedHashMap的特别属性

LinkedHashMap虽然继承了HashMap的结构存储数据,但是除了HashMap的相关属性以外,还特别添加了:

3.1、Header属性,来存储双向链表的关系。

3.2、accessOrder属性,这个属性主要是控制链表的顺序的,如果accessOrder为false(默认为false),遍历LinkedHashMap的时候,返回的数据顺序为写入的顺序,如果为true,则返回数据的顺序为读取的顺序。

注意:如果accessOrder为true,get方法中也在修改LinkedHashMap,所以不能一边遍历LinkedHashMap,一边从LinkedHashMap中get获取对象,否则会抛出ConcurrentModificationException

下面的例子主要是针对accessOrder为true的证实

public class TestLinkedHashMap {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		LinkedHashMap hm1 = new LinkedHashMap(16, 0.75f,true);
		hm1.put(1,"1");
		hm1.put(2,"2");
		hm1.put(3,"3");
		hm1.put(4,"4");
		hm1.put(5,"5");
		
		hm1.get(2);
		hm1.get(4);
		hm1.get(3);
		hm1.get(5);
		hm1.get(1);
		
		Iterator iter1 = hm1.keySet().iterator();
		while(iter1.hasNext()){
			System.out.println(iter1.next());
		}

	}

}

结果为:

2
4
3
5
1

你可能感兴趣的:(java集合)