HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap
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()方法。
123456789101112131415161718192021222324252627282930313233 | 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()); } } } |
輸出:
12345 | 4 white dog - 5 black dog - 15 red dog - 10 white dog - 20 |
註意,我們錯誤的將”white dogs”添加了兩次,但是HashMap卻接受了兩只”white dogs”。這不合理(因為HashMap的鍵不應該重復),我們會搞不清楚真正有多少白色的狗存在。
Dog類應該定義如下:
12345678910111213141516171819 | 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" ; } } |
現在輸出結果如下:
1234 | 3 red dog - 10 white dog - 20 black dog - 15 |
輸出結果如上是因為HashMap不允許有兩個相等的元素存在。默認情況下(也就是類沒有實現hashCode()和equals()方法時),會使用Object類中的這兩個方法。Object類中的hashCode()對於不同的對象會返回不同的整數,而只有兩個引用指向的同樣的對象時equals()才會返回true。如果你不是很了解hashCode()和equals()的規則,可以看看這篇文章。
來看看HashMap最常用的方法,如叠代、打印等。
3. TreeMap
TreeMap的鍵按順序排列。讓我們先看個例子看看什麽叫作“鍵按順序排列”。
123456789101112131415161718192021222324252627282930313233343536 | 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()); } } } |
輸出:
123 | 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接口。
12345678910111213141516171819202122232425262728293031323334353637 | 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()); } } } |
輸出:
123 | red dog - 10 black dog - 15 white dog - 20 |
結果根據鍵的排列順序進行輸出,在我們的例子中根據size排序的。
如果我們將“Dog d4 = new Dog(“white”, 10);”替換成“Dog d4 = new Dog(“white”, 40);”,那麽輸出會變成:
1234 | 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基礎上增加的特性就是保存了插入對象的順序。
123456789101112131415161718192021222324252627282930313233343536373839 | 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()); } } } |
輸出:
123 | red dog - 10 black dog - 15 white dog - 20 |
如果我們使用HashMap的話,輸出將會如下,會打亂插入的順序:
123 | red dog - 10 white dog - 20 black dog - 15 |
譯文鏈接: http://www.importnew.com/8658.html
[ 轉載請保留原文出處、譯者和譯文鏈接。]
HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap