Map是Java中最重要的数据结构之一。在这篇文章中,我将说明如何使用不同类型的地图,例如HashMap,TreeMap,HashTable和LinkedHashMap。
1.map概述
Java SE中有4种常用的Map实现 - HashMap,TreeMap,Hashtable和LinkedHashMap。如果我们只使用一个句子来描述每个实现,那么它将如下:
- HashMap实现为哈希表,键或值没有排序
- TreeMap基于红黑树结构实现,并按密钥排序。
- LinkedHashMap保留插入顺序
- 与HashMap相比,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());
}
}
}
输出:
请注意,我们错误地添加了两次“white dog”,但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";
}
}
现在输出是:
原因是HashMap不允许两个相同的元素。默认情况下,使用Object类中实现的hashCode()和equals()方法。默认的hashCode()方法为不同的对象提供不同的整数,而equals()方法仅在两个引用引用同一对象时返回true。
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());
}
}
}
输出:
由于TreeMaps是按键排序的,因此key的对象必须能够相互比较,这就是它必须实现Comparable接口的原因。例如,您使用String作为键,因为String实现了Comparable接口。
让我们改变狗,让它具有可比性。
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());
}
}
}
输出:
它按键排序,即在这种情况下的狗大小。
如果“Dog d4 = new Dog(“white”, 10);” 被替换为“Dog d4 = new Dog(“white”, 40);”,输出将是
原因是TreeMap现在使用compareTo()方法来比较键。不同的尺寸使不同的狗!
4.Hashtable
HashMap类大致相当于Hashtable,除了它是不同步的并且允许空值。
5.LinkedHashMap
LinkedHashMap是HashMap的子类。这意味着它继承了HashMap的功能。此外,链表保留了插入顺序。
让我们使用与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());
}
}
}
输出是:
不同之处在于,如果我们使用HashMap,则输出可能如下 - 不保留插入顺序。