• HashMap vs TreeMap vs Hashtable vs LinkedHashMap


    Map是一个重要的数据结构,本篇文章将介绍如何使用不同的Map,如HashMap,TreeMap,HashTable和LinkedHashMap。

    Map概览

    Java中有四种常见的Map实现,HashMap,TreeMap,HashTable和LinkedHashMap,我们可以使用一句话来描述各个Map,如下:

    • HashMap:基于散列表实现,是无序的;
    • TreeMap:基于红黑树实现,按Key排序;
    • LinkedHashMap:保存了插入顺序;
    • Hashtable:是同步的,与HashMap类似;

    HashMap

    如果HashMap的Key是自己定义的对象,那么一般需要覆盖equals()和hashCode()方法,且要遵循他们之间的约定。

    package simplejava;
    
    import java.util.HashMap;
    import java.util.Map.Entry;
    
    class Dog {
        String color;
    
        Dog(String c) {
            color = c;
        }
    
        public String toString() {
            return color + " dog";
        }
    }
    
    public class Q26 {
    
        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
    red dog - 10
    white dog - 20
    black dog - 15

    注意,我们不小心添加了两个"white dogs“,但是HashMap仍然存储它。这是不合理的,现在我们困惑到底有多少条白狗存入了HashMap,5还是20呢。

    其实,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。如果你不是很清楚,可以自己检验下hashCode()和equals()之间的关系。

    举个例子,可以检验下HashMap中最常用的方法,如iteration,print等。

    TreeMap

    TreeMap是按key排序的,让我们先看下如下代码,了解其“按key排序”思想。

    package simplejava;
    
    import java.util.Map.Entry;
    import java.util.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 Q26 {
    
        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: simplejava.Dog cannot be cast to java.lang.Comparable
        at java.util.TreeMap.compare(TreeMap.java:1188)
        at java.util.TreeMap.put(TreeMap.java:531)
        at simplejava.Q26.main(Q26.java:34)

    由于TreeSet是基于Key排序的,所以作为key的对象需要相互比较,这就是为什么key需要实现Comparable接口。举个例子,你可以使用字符串作为Key,因为String已经实现了Comparable接口。

    现在,让我们改变一下Dog,让它可比较,如下:

    package simplejava;
    
    import java.util.Map.Entry;
    import java.util.TreeMap;
    
    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 Q26 {
    
        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的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意味着不同的dogs。

    HashTable

    参考java文档:HashMap与HashTable基本类似,除了非同步和允许null外。

    LinkedHashMap

    LinkedHashMap是HashMap的子类,意味着它继承了HashMap的特性,除此之外,LinkedHashMap还保存了插入顺序。

    让我们使用同样的代码,然后将HashMap替换成LinkedHashMap,如下:

    package simplejava;
    
    import java.util.LinkedHashMap;
    import java.util.Map.Entry;
    
    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 Q26 {
    
        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

    如果我们使用HashMap,结果如下,区别在于没有保存插入顺序:

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

    更多阅读:ArrayList vs. LinkedList vs. Vector

    译文链接:http://www.programcreek.com/2013/03/hashmap-vs-treemap-vs-hashtable-vs-linkedhashmap/

  • 相关阅读:
    Swing中GridBagLayout布局的使用
    Android下Slidingmenu和actionbarsherlock的使用
    Swing基础知识
    Android下的ActionBar
    android下ADT的更新
    spark插件入门完整版本
    IOS开发准备 资料集锦
    Java调用本地浏览器
    Android源码在线查看网址
    Android中ProgressBar
  • 原文地址:https://www.cnblogs.com/chenpi/p/5505705.html
Copyright © 2020-2023  润新知