HashMap vs. TreeMap vs. Hashtable vs.LinkedHashMap

1. Map概览

Java SE中有四种常见的Map实现——HashMap, TreeMap, Hashtable和LinkedHashMap。若是咱们使用一句话来分别归纳它们的特色,就是:java

  • HashMap就是一张hash表,键和值都没有排序。安全

  • TreeMap以红-黑树结构为基础,键值按顺序排列。oop

  • LinkedHashMap保存了插入时的顺序。this

  • Hashtable是同步的(而HashMap是不一样步的)。因此若是在线程安全的环境下应该多使用HashMap,而不是Hashtable,由于Hashtable对同步有额外的开销。spa


  • HashMap线程

  • 若是HashMap的键(key)是自定义的对象,那么须要按规则定义它的equals()和hashCode()方法code

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

输出:htm

1
2
3
4
5
4
white dog - 5
black dog - 15
red dog - 10
white dog - 20

注意,咱们错误的将”white dogs”添加了两次,可是HashMap却接受了两只”white dogs”。这不合理(由于HashMap的键不该该重复),咱们会搞不清楚真正有多少白色的狗存在。对象

Dog类应该定义以下:排序

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";
    }
}

如今输出结果以下:

1
2
3
4
3
red dog - 10
white dog - 20
black dog - 15

输出结果如上是由于HashMap不容许有两个相等的元素存在。默认状况下(也就是类没有实现hashCode()和equals()方法时),会 使用Object类中的这两个方法。Object类中的hashCode()对于不一样的对象会返回不一样的整数,而只有两个引用指向的一样的对象时 equals()才会返回true。若是你不是很了解hashCode()和equals()的规则,能够看看这篇文章

来看看HashMap最经常使用的方法,如迭代、打印等。

3. TreeMap

TreeMap的键按顺序排列。让咱们先看个例子看看什么叫做“键按顺序排列”。

package javaBasic;

import java.util.TreeMap;
import java.util.Map.Entry;

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 TreeMapTest {
    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: javaBasic.Dog
    at java.util.TreeMap.compare(Unknown Source)
    at java.util.TreeMap.put(Unknown Source)
    at javaBasic.TreeMapTest.main(TreeMapTest.java:35)


由于TreeMap按照键的顺序进行排列对象,因此键的对象之间须要可以比较,因此就要实现Comparable接口。你可使用String做为键,String已经实现了Comparable接口。

咱们来修改下Dog类,让它实现Comparable接口。

package javaBasic;

import java.util.TreeMap;
import java.util.Map.Entry;

class Dog implements Comparable<Dog>{
    String color;
    int size;
 
    Dog(String c, int s) {
        color = c;
        size = s;
    }
 
    public String toString(){  
        return color + " dog";
    }
 
    
    public int compareTo(Dog o) {
        return  o.size - this.size;
    }

}

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

输出:

1
2
3
red dog - 10
black dog - 15
white dog - 20

结果根据键的排列顺序进行输出,在咱们的例子中根据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()方法来比较键值的大小,size不相等的狗是不一样的狗。

4. Hashtable

Java文档写道:

HashMap类和Hashtable类几乎相同,不一样之处在于HashMap是不一样步的,也容许接受null键和null值。

5. LinkedHashMap

LinkedHashMap是HashMap的子类,因此LinkedHashMap继承了HashMap的一些属性,它在HashMap基础上增长的特性就是保存了插入对象的顺序。

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

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

若是咱们使用HashMap的话,输出将会以下,会打乱插入的顺序:.

package javaBasic;

import java.util.HashMap;
import java.util.Map.Entry;


/**
 * HashMap就是一张hash表,键和值都没有排序。
 * @author markGao
 *
 */
 
public class HashMapTest {
    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
        //若是咱们使用HashMap的话,输出将会以下,会打乱插入的顺序:
        for (Entry<Dog, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey().toString() + " - " + entry.getValue());
        }
    }
}
1
2
3
red dog - 10
white dog - 20
black dog - 15
相关文章
相关标签/搜索