文章来自http://blog.csdn.net/windsunmoon/article/details/46390451
看起来晕过段时间看
Map是键值对,也是常用的数据结构。Map接口定义了map的基本行为,包括最核心的get和put操作,此接口的定义的方法见下图:
JDK中有不同的的map实现,分别适用于不同的应用场景,如线程安全的hashTable和非线程安全的hashMap.
如下图是JDK中map接口的子类UML类图,其中有个特例Dictionary已经不建议使用:
Map接口中的方法我们需要关注的就是get、put 和迭代器相关的方法如entrySet()、keySet()、values()方法。
Entry
在开始分析map之前,首先了解map中元素的存储,我们知道map可以认为是键值对的集合,java中map使用Entry存储键值对,这是一个接口,其定义如下,简单明了,接口方法主要是对键和值进行操作。
AbstractMap
Map接口的抽象实现,见以下示例实现代码:
HashMap
hashMap继承abstractMap,是相当常用的数据结构,采用hash散列的思想,可以在O(1)的时间复杂度内插入和获取数据。其基本实现可以分析上个小节中的抽象方法,文章
浅析HashMap的实现和性能分析 已经对hashMap的实现、put和get操作进行了较详细的说明。这里不再赘述,关键看他的迭代器实现,这里只分析下entrySet()方法,而keySet()和values()方法实现与之一脉相承。
关于迭代器,见下面摘出的部分源码和相关注释:
HashTable
实现和hashMap基本一致,只是在方法上加上了同步操作。多线程环境可以使用它。不过现在有ConcurrentHashMap了,在高并发的时候,可以用它替换hashtable.
LinkedHashMap
hashMap可能在某些场景下不符合要求,因为放入到其中的元素是无序的。而LinkedHashMap则在一定程度上解决这个问题。
其在实现上继承了HashMap,在存储上扩展haspMap.enteySet,加入了before、after字段,把hashMap的元素用双向链表连接了起来。这个双向链表决定了它的遍历顺序。其顺序通常是插入map中的顺序,但是它有一个字段accessOrder当为true时,遍历顺序将是LRU的效果。
研究它的有序性,我们可以从put方法、get方法和遍历的方法入手,首先看get方法:
Put方法:
遍历迭代直接使用双向链表进行迭代接口,这里不赘述,可以看源码很容易理解。注意的是实现上市覆盖了父类中相关的生成迭代器的方法。
TreeMap和CurrentHashMap都可以单独开一篇文章来分析了。这里简单说下。TreeMap是基于b树map,根据key排序。CurrentHashMap是并发包中的一个强大的类,适合多线程高并发时数据读写。
package com.te;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
class Test {
public void fun() {
Map<String,Object> map=new ConcurrentHashMap();//数据存放无序的
map.put("arg1", 1);
map.put("arg2", 2);
map.put("arg3", 3);
map.put("arg4", 4);
Map<String,Object> map1=new ConcurrentHashMap();//数据存放无序的
map1.put("arg1", 1);
map1.put("arg2", 2);
map1.put("arg3", 3);
map1.put("arg4", 4);
Map<String,Object> map2=new LinkedHashMap();//数据存放有序
map2.put("arg1", 1);
map2.put("arg2", 2);
map2.put("arg3", 3);
map2.put("arg4", 4);
for(String key:map.keySet()) {
System.out.println(key);
System.out.println(map.get(key));
System.out.println(map.containsKey(key));
System.out.println(map.containsValue(map.containsKey(key)));
}
for(String key:map1.keySet()) {
System.out.println(key);
System.out.println(map1.get(key));
System.out.println(map1.containsKey(key));
System.out.println(map1.containsValue(map1.containsKey(key)));
}
for(String key:map2.keySet()) {
System.out.println(key);
System.out.println(map2.get(key));
System.out.println(map2.containsKey(key));
System.out.println(map2.containsValue(map2.containsKey(key)));
}
}
}
public class Testnull {
public static void main(String[] args) {
// TODO Auto-generated method stub
//应该是引用不同于指针,引用中既包含指向对象的指针、又包含指向类的指针,
//test中指向对象的指针确实为空,但指向Test的指针可不为空啊
Test test=new Test();
//test.hello();
test.fun();
}
}