4.4 HashMap vs. Treemap vs.HashTable vs.LinkedHashMap

Map 是Java中最重要的数据结构。在这篇文章中,我将演示如何使用不同类型的地图,如HashMap、TreeMap、HashTable和LinkedHashMap。

1. Map 概述

4.4 HashMap vs. Treemap vs.HashTable vs.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 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());
        }
    }
}

输出:

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 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());
        }
    }
}

输出:

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{
    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());
        }
    }
}

输出:

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 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());
        }       
    }
}

输出:

red dog - 10
black dog - 15
white dog - 20

不同的是,如果我们使用HashMap的输出可能如下,插入的顺序不会保留。

red dog - 10
white dog - 20
black dog - 15

你可能感兴趣的:(4.4 HashMap vs. Treemap vs.HashTable vs.LinkedHashMap)