Java Map的几种类型

Map类型

插入是否有序

顺序特点

HashMap

无序

-

LinkedHashMap

有序

记录插入顺序

TreeMap

有序

默认升序

Map主要用于存储健值对,根据键得到值,因此不允许键重复(若重复则覆盖),但允许值重复。

HashMap

Hashmap 是一个最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。

遍历时,取得数据的顺序是完全随机的。

HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null。

HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步能力,或者使用ConcurrentHashMap。

Hashtable

Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:

1. 它不允许记录的键或者值为空。

2. 它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。

LinkedHashMap

LinkedHashMap 保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和容量有关。

TreeMap

TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。

比较:

一般情况下,我们用的最多的是HashMap,HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map中插入、删除和定位元素,HashMap 是最好的选择。

TreeMap取出来的是排序后的键值对。但如果要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

LinkedHashMap是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。

示例:

public class Test {
public static void main(String[] argv) {
Map hashMap = new HashMap();
Map treeMap = new TreeMap();
Map linkedHashMap = new LinkedHashMap();
System.out.println("test HashMap:");
testMap(hashMap);
System.out.println("test TreeMap:");
testMap(treeMap);
System.out.println("test LinkedHashMap:");
testMap(linkedHashMap);
}
static void testMap(Map map) {
map.put(4, 1);
map.put(3, 2);
map.put(2, 3);
map.put(1, 4);
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
// 输出:
/*
test HashMap:
1 : 4
2 : 3
3 : 2
4 : 1
test TreeMap:
1 : 4
2 : 3
3 : 2
4 : 1
test LinkedHashMap:
4 : 1
3 : 2
2 : 3
1 : 4
*/

HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key。

Map的key和Set都有一个共同的特性就是集合的唯一性。TreeMap更是多了一个排序的功能。

hashCode()和equals()是HashMap用的,因为无需排序所以只需要关注定位和唯一性即可。

a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的。

b. hash表中的一个索引处存放的是一张链表,所以还要通过equals方法循环比较链上的每一个对象,才可以真正定位到键值对应的Entry。

c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value。

由于TreeMap需要排序,所以需要一个Comparator**为键值比较大小**,也是用来Comparator定位的。

a. Comparator可以在创建TreeMap时指定,传参。

b. 如果创建时没有确定,那么就会使用key.compare()方法,这就要求key必须实现Comparator接口。

c. TreeMap是使用Tree数据结构实现的,所以使用Comparator接口就可以完成定位了。

注意:

1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。

2、Set和Collection拥有一模一样的接口。

3、List接口可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)…(add/get)

4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。

5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。

HashMap会利用对象的hashCode来快速找到key。

哈希:

哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。

我们都知道所有存储结构中,array查找速度是最快的。所以可以加速查找。

发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。

6、Map中元素,可以将key序列、value序列单独抽取出来。

使用keySet()抽取key序列,将map中的所有keys生成一个Set。

使用values()抽取value序列,将map中的所有values生成一个Collection。

为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。