您的位置:首页 > 其它

集合框架map学习笔记一LinkedHashMap

2013-03-26 22:34 92 查看
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<K,V> 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<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<K,V>(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<K,V> 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<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;
}

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


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<Integer, String> hm1 = new LinkedHashMap<Integer, String>(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: