Map是最重要的數據結構。這篇文章中,我會帶你們看看HashMap, TreeMap, HashTable和LinkedHashMap的區別。
1. Map概覽
Java SE中有四種常見的Map實現——HashMap, TreeMap, Hashtable和LinkedHashMap。如果我們使用一句話來分別概括它們的特點,就是:
- HashMap就是一張hash表,鍵和值都沒有排序。
- TreeMap以紅-黑樹結構爲基礎,鍵值按順序排列。
- LinkedHashMap保存了插入時的順序。
- Hashtable是同步的(而HashMap是不同步的)。所以如果在線程安全的環境下應該多使用HashMap,而不是Hashtable,因爲Hashtable對同步有額外的開銷。
- HashMap
如果HashMap的鍵(key)是自定義的對象,那麼需要按規則定義它的equals()和hashCode()方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
class
Dog { String
color; Dog(String
c) { color
= c; } public
String toString(){ return
color + "
dog" ; } } public
class
TestHashMap { public
static
void
main(String[] args) { HashMap
hashMap = new
HashMap(); Dog
d1 = new
Dog( "red" ); Dog
d2 = new
Dog( "black" ); Dog
d3 = new
Dog( "white" ); Dog
d4 = new
Dog( "white" ); hashMap.put(d1,
10 ); hashMap.put(d2,
15 ); hashMap.put(d3,
5 ); hashMap.put(d4,
20 ); //print
size System.out.println(hashMap.size()); //loop
HashMap for
(Entry entry : hashMap.entrySet()) { System.out.println(entry.getKey().toString()
+ "
- "
+ entry.getValue()); } } } |
輸出:
1
2
3
4
5
|
4 white
dog - 5 black
dog - 15 red
dog - 10 white
dog - 20 |
注意,我們錯誤的將”white dogs”添加了兩次,但是HashMap卻接受了兩隻”white dogs”。這不合理(因爲HashMap的鍵不應該重複),我們會搞不清楚真正有多少白色的狗存在。
Dog類應該定義如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class
Dog { String
color; Dog(String
c) { color
= c; } public
boolean
equals(Object o) { return
((Dog) o).color == this .color; } public
int
hashCode() { return
color.length(); } public
String toString(){ return
color + "
dog" ; } } |
現在輸出結果如下:
1
2
3
4
|
3 red
dog - 10 white
dog - 20 black
dog - 15 |
輸出結果如上是因爲HashMap不允許有兩個相等的元素存在。默認情況下(也就是類沒有實現hashCode()和equals()方法時),會使用Object類中的這兩個方法。Object類中的hashCode()對於不同的對象會返回不同的整數,而只有兩個引用指向的同樣的對象時equals()纔會返回true。如果你不是很瞭解hashCode()和equals()的規則,可以看看這篇文章。
來看看HashMap最常用的方法,如迭代、打印等。
3. TreeMap
TreeMap的鍵按順序排列。讓我們先看個例子看看什麼叫作“鍵按順序排列”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
class
Dog { String
color; Dog(String
c) { color
= c; } public
boolean
equals(Object o) { return
((Dog) o).color == this .color; } public
int
hashCode() { return
color.length(); } public
String toString(){ return
color + "
dog" ; } } public
class
TestTreeMap { public
static
void
main(String[] args) { Dog
d1 = new
Dog( "red" ); Dog
d2 = new
Dog( "black" ); Dog
d3 = new
Dog( "white" ); Dog
d4 = new
Dog( "white" ); TreeMap
treeMap = new
TreeMap(); treeMap.put(d1,
10 ); treeMap.put(d2,
15 ); treeMap.put(d3,
5 ); treeMap.put(d4,
20 ); for
(Entry entry : treeMap.entrySet()) { System.out.println(entry.getKey()
+ "
- "
+ entry.getValue()); } } } |
輸出:
1
2
3
|
Exception
in thread "main" java.lang.ClassCastException: collection.Dog cannot be cast to java.lang.Comparable at
java.util.TreeMap.put(Unknown Source) at
collection.TestHashMap.main(TestHashMap.java:35) |
因爲TreeMap按照鍵的順序進行排列對象,所以鍵的對象之間需要能夠比較,所以就要實現Comparable接口。你可以使用String作爲鍵,String已經實現了Comparable接口。
我們來修改下Dog類,讓它實現Comparable接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
class
Dog implements
Comparable<Dog>{ String
color; int
size; Dog(String
c, int
s) { color
= c; size
= s; } public
String toString(){ return
color + "
dog" ; } @Override public
int
compareTo(Dog o) { return
o.size - this .size; } } public
class
TestTreeMap { public
static
void
main(String[] args) { Dog
d1 = new
Dog( "red" ,
30 ); Dog
d2 = new
Dog( "black" ,
20 ); Dog
d3 = new
Dog( "white" ,
10 ); Dog
d4 = new
Dog( "white" ,
10 ); TreeMap
treeMap = new
TreeMap(); treeMap.put(d1,
10 ); treeMap.put(d2,
15 ); treeMap.put(d3,
5 ); treeMap.put(d4,
20 ); for
(Entry entry : treeMap.entrySet()) { System.out.println(entry.getKey()
+ "
- "
+ entry.getValue()); } } } |
輸出:
1
2
3
|
red
dog - 10 black
dog - 15 white
dog - 20 |
結果根據鍵的排列順序進行輸出,在我們的例子中根據size排序的。
如果我們將“Dog d4 = new Dog(“white”, 10);”替換成“Dog d4 = new Dog(“white”, 40);”,那麼輸出會變成:
1
2
3
4
|
white
dog - 20 red
dog - 10 black
dog - 15 white
dog - 5 |
這是因爲TreeMap使用compareTo()方法來比較鍵值的大小,size不相等的狗是不同的狗。
4. Hashtable
Java文檔寫道:
HashMap類和Hashtable類幾乎相同,不同之處在於HashMap是不同步的,也允許接受null鍵和null值。
5. LinkedHashMap
LinkedHashMap is a subclass of HashMap. That means it inherits the features of HashMap. In addition, the linked list preserves the insertion-order.
Let’s replace the HashMap with LinkedHashMap using the same code used for HashMap.
LinkedHashMap是HashMap的子類,所以LinkedHashMap繼承了HashMap的一些屬性,它在HashMap基礎上增加的特性就是保存了插入對象的順序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
class
Dog { String
color; Dog(String
c) { color
= c; } public
boolean
equals(Object o) { return
((Dog) o).color == this .color; } public
int
hashCode() { return
color.length(); } public
String toString(){ return
color + "
dog" ; } } public
class
TestHashMap { public
static
void
main(String[] args) { Dog
d1 = new
Dog( "red" ); Dog
d2 = new
Dog( "black" ); Dog
d3 = new
Dog( "white" ); Dog
d4 = new
Dog( "white" ); LinkedHashMap
linkedHashMap = new
LinkedHashMap(); linkedHashMap.put(d1,
10 ); linkedHashMap.put(d2,
15 ); linkedHashMap.put(d3,
5 ); linkedHashMap.put(d4,
20 ); for
(Entry entry : linkedHashMap.entrySet()) { System.out.println(entry.getKey()
+ "
- "
+ entry.getValue()); }
} } |
輸出:
1
2
3
|
red
dog - 10 black
dog - 15 white
dog - 20 |
如果我們使用HashMap的話,輸出將會如下,會打亂插入的順序:
1
2
3
|
red
dog - 10 white
dog - 20 black
dog - 15 |
譯文鏈接: http://www.importnew.com/8658.html
[ 轉載請保留原文出處、譯者和譯文鏈接。]