Map 是Java中最重要的数据结构。在这篇文章中,我将演示如何使用不同类型的地图,如HashMap、TreeMap、HashTable和LinkedHashMap。
1. Map 概述
在Java SE中有4种常用的Map实现:HashMap、TreeMap、Hashtable和LinkedHashMap。如果我们只用一句话来描述每个实现,将是:
HashMap 用哈希表实现,并且对键或值没有排序。
TreeMap 在红黑树的机构上实现,它按照Key来排序。
LinkedHashMap 保持着插入的顺序。
Hashtable 是同步的的HashMap,它有一个同步的开销。
在线程安全中使用它。
2. HashMap
如果HashMap的键是自定义对象,那么需要遵循equals()和hashCode()约定。
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<Dog, Integer> hashMap = new HashMap<Dog, Integer>();
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<Dog, Integer> entry : hashMap.entrySet()) {
System.out.println(entry.getKey().toString() + " - " + entry.getValue());
}
}
}
输出:
4
white dog - 5
black dog - 15
red dog - 10
white dog - 20
注意这里,我们添加了“while dogs”两次的错误,但是HashMap接受它。这没有意义,因为现在我们困惑这有多少white dog 真的在那里。
Dog类如下定义:
class Dog {
String color;
Dog(String c) {
color = c;
}
public boolean equals(Object o) {
return ((Dog) o).color.equals(this.color);
}
public int hashCode() {
return color.length();
}
public String toString(){
return color + " dog";
}
}
现在输出如下:
3
red dog - 10
white dog - 20
black dog - 15
原因是HashMap不准许两个相同元素。默认情况下,在使用Object类的hashCode()和equals()方法时候。默认的hashCode()方法为不同对象提供不同的整数,equal()方法只有当两个引用指向同一个对象时才返回true。
3. TreeMap
一个TreeMap是按照Keys排序的。让我们先来看看下面的例子来理解“按键排序”的想法。
class Dog {
String color;
Dog(String c) {
color = c;
}
public boolean equals(Object o) {
return ((Dog) o).color.equals(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<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
treeMap.put(d1, 10);
treeMap.put(d2, 15);
treeMap.put(d3, 5);
treeMap.put(d4, 20);
for (Entry<Dog, Integer> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + " - " + entry.getValue());
}
}
}
输出:
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)
由于TreeMaps按键排序,key的对象必须能够相互比较,这就是为什么它必须实现Comparable接口。例如,你可以使用String作为键,因为String实现了Comparable接口。
让我们改变Dog类,使它是可以比较的。
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<Dog, Integer> treeMap = new TreeMap<Dog, Integer>();
treeMap.put(d1, 10);
treeMap.put(d2, 15);
treeMap.put(d3, 5);
treeMap.put(d4, 20);
for (Entry<Dog, Integer> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + " - " + entry.getValue());
}
}
}
输出:
red dog - 10
black dog - 15
white dog - 20
他们按照key排序,在这个例子中是dog的size。
如果“Dog d4 = new Dog(“white”,10);” 用"Dog d4 = new Dog("White",40);"替换,输出将是:
white dog - 20
red dog - 10
black dog - 15
white dog - 5
原因是TreeMap现在用CompareTo()方法比较key,不同的size是不同的dog对象。
4. Hashtable
通过Java的Doc得知,HashMap类大致相当于Hashtable,除了它是未同步的并且准许null。
5. LinkedHashMap
LinkedHashMap是HashMap的子类。这意味着它集成了HashMap的特性。此外,LinkedHashMap保留了插入的顺序。
让我们使用与HashMap相同的代码用LinkedHashMap替换HashMap。
class Dog {
String color;
Dog(String c) {
color = c;
}
public boolean equals(Object o) {
return ((Dog) o).color.equals(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<Dog, Integer> linkedHashMap = new LinkedHashMap<Dog, Integer>();
linkedHashMap.put(d1, 10);
linkedHashMap.put(d2, 15);
linkedHashMap.put(d3, 5);
linkedHashMap.put(d4, 20);
for (Entry<Dog, Integer> entry : linkedHashMap.entrySet()) {
System.out.println(entry.getKey() + " - " + entry.getValue());
}
}
}
输出:
red dog - 10
black dog - 15
white dog - 20
不同的是,如果我们使用HashMap的输出可能如下,插入的顺序不会保留。
red dog - 10
white dog - 20
black dog - 15