• HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap


    	<div class="copyright-area">本文由 <a href="http://www.importnew.com">ImportNew</a> - <a href="http://www.importnew.com/author/tangxiaojuan">唐小娟</a> 翻译自 <a target="_blank" href="http://www.programcreek.com/2013/03/hashmap-vs-treemap-vs-hashtable-vs-linkedhashmap/" class="external" rel="nofollow">Programcreek</a>。欢迎加入<a href="http://group.jobbole.com/category/feedback/trans-team/" class="external" rel="nofollow" target="_blank">翻译小组</a>。转载请见文末要求。</div>
    

    Map是最重要的数据结构。这篇文章中,我会带你们看看HashMap, TreeMap, HashTable和LinkedHashMap的区别。

    1. Map概览

    Java SE中有四种常见的Map实现——HashMap, TreeMap, Hashtable和LinkedHashMap。如果我们使用一句话来分别概括它们的特点,就是:

    • HashMap就是一张hash表,键和值都没有排序。
    • TreeMap以红-黑树结构为基础,键值按顺序排列。
    • LinkedHashMap保存了插入时的顺序。
    • Hashtable是同步的(而HashMap是不同步的)。所以如果在线程安全的环境下应该多使用HashMap,而不是Hashtable,因为Hashtable对同步有额外的开销。
    1. HashMap

    如果HashMap的键(key)是自定义的对象,那么需要按规则定义它的equals()和hashCode()方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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());
            }
        }
    }

    输出:

    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类应该定义如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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的键按顺序排列。让我们先看个例子看看什么叫作“键按顺序排列”。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    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 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());
            }
        }
    }

    输出:

    1
    2
    3
    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)

    因为TreeMap按照键的顺序进行排列对象,所以键的对象之间需要能够比较,所以就要实现Comparable接口。你可以使用String作为键,String已经实现了Comparable接口。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    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 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());
            }
        }
    }

    输出:

    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);”,那么输出会变成:

    1
    2
    3
    4
    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 is a subclass of HashMap. That means it inherits the features of HashMap. In addition, the linked list preserves the insertion-order.

    Let’s replace the HashMap with LinkedHashMap using the same code used for HashMap.

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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());
            }      
        }
    }

    输出:

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

    如果我们使用HashMap的话,输出将会如下,会打乱插入的顺序:

    1
    2
    3
    red dog - 10
    white dog - 20
    black dog - 15
        原文链接: <a target="_blank" href="http://www.programcreek.com/2013/03/hashmap-vs-treemap-vs-hashtable-vs-linkedhashmap/">Programcreek</a>    翻译: <a href="http://www.importnew.com"> ImportNew.com </a> - <a href="http://www.importnew.com/author/tangxiaojuan">唐小娟</a><br>译文链接: <a href="http://www.importnew.com/8658.html">http://www.importnew.com/8658.html</a><br>[ <span style="color:#ff0000"><b>转载请保留原文出处、译者和译文链接。</b></span>]<br><br>
    
    </div>
  • 相关阅读:
    Oracle11g聚合函数
    和为S的连续正数数列,动态规划,C++
    统计一个数组在排序数组中出现的次数,C++,二分查找
    寻找两个链表的第一个公共子节点,C++
    二维数组中的查找
    数组中的逆序对,C++,分治算法
    得到从小到大的第N个丑数的三种方式(C++)一维动态规划
    连续字数组的最大和(Java)一个int数组,求其中的最大的连续数的和
    n个整数,求这中间最小的k个整数(Java)
    两个字符串的最长公共子串求法(C++、动态规划)
  • 原文地址:https://www.cnblogs.com/jpfss/p/7843832.html
Copyright © 2020-2023  润新知