HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap 对比

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

注意输出顺序与插入顺序是一样的。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值