Map是Java中最重要的数据结构之一。因此我将演示如何使用不同类型的map,比如HashMap, TreeMap, HashTable and LinkedHashMap.
1. Map Overview
一句话简要概括每一个:
HashMap:是被实现为hash table,键值排列是无序的。
TreeMap: 是基于红黑树实现的,根据键进行排序的。
LinkedHashMap:根据插入顺序排序。
Hashtable:是同步的,对比HashMap多了同步的开销。
这就是为什么HashMap应使用在线程安全的情况下。
2. 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
从结果可以看出,有两个white dog作为键存在,这是不对的,key不唯一了。
更改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()方法为截然不同的对象提供了不同的整数,而equals()方法只有在两个引用引用同一对象时才返回true。
默认Object.equals()使用==作为比较,很显然对象这样对比是错误的。
3. TreeMap
TreeMap是按键排序的。让我们首先看一下下面的例子来理解“按键排序”的想法。
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是按键排序的,所以键的对象必须能够相互比较,这就是为什么它必须实现可比较的接口。例如,您使用弦乐作为键,因为String实现了可比较的接口。
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
如果Dog d4 = new Dog(“white”, 10); 修改为Dog d4 = new Dog(“white”, 40);
结果输出:
white dog - 20
red dog - 10
black dog - 15
white dog - 5
4. Hashtable
HashMap类大致相当于Hashtable,只不过它是不同步的,并且不允许key和value为null。
5. LinkedHashMap
LinkedHashMap是HashMap的子类。这意味着它继承了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
注意输出顺序与插入顺序是一样的。