zoukankan      html  css  js  c++  java
  • 常用Map实现类对比

    翻译人员: 铁锚

    翻译时间: 2013年12月12日

    原文链接: HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap


    Map 是最常用的数据结构之一. 
    Map 的字面翻译是映射(地图就是一种映射).
    本文将为你展示如何使用各种不同的map,包括 HashMap, TreeMap, HashTable 以及 LinkedHashMap.
    1. Map 概述

    图1

    在JavaSE中,对Map的实现主要包括: HashMap, TreeMap, HashTable 和 LinkedHashMap.
    如果每个类都用一句话来描述,则表述如下:
    • HashMap 使用哈希表(hash table)实现, 在 keys 和/或 values 之中,都是无序的.
    • TreeMap 基于红黑树(red-black tree)数据结构实现, 按 key 排序.
    • LinkedHashMap 保持者插入顺序.
    • Hashtable 与HashMap实现方式一样,但Hashtable属于同步(synchronized)的.
    所以如果代码是线程安全的,那么应该使用HashMap,因为Hashtable的同步是有一定量的运行代价的。而现今对于需要同步的Map,使用 ConcurrentHashMap 也比 Hashtable 有更高的效率。
    2. HashMap
    如果HashMap中的key使用的是自定义的类对象,那么需要遵守 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 dogs",但是HashMap 接受了,这严格来说是没意义的,因为现在对"white dogs"的数量产生了混淆.
    修正后的 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";
        }
    }
    再运行新的代码,结果如下所示:
    3
    red dog – 10
    white dog – 20
    black dog – 15
    原因在于 HashMap 不运行两个相同的元素作为KEY.
    如果没有重写,使用的就会是 Object 类实现的 hashCode() 和 equals() 方法
    默认的 hashCode() 方法实现对每个不同的对象返回不同的整数.
    默认的 equals() 方法只比较两个引用是否指向同一个实际对象.
    如果你还有疑惑,请阅读:  equals()与hashCode()方法协作约定
    3. TreeMap
    TreeMap是根据key排序的.我们先看下面的示例来加深 "按key排序" 的印象.
    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<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)
    既然 TreeMap 是按key排序的,那么key对象就必须可以和另一个对象作比较,因此必须实现 Comparable 接口。
    当然,你也可以使用 String 对象作为key,因为 String 类已经实现了 Comparable 接口。
    下面,我们修改 Dog 类的代码,使其实现Comparable:
    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
    这就是根据key对象排序的结果,此处我们使用了 size(尺寸)来比较 dog.
    如果我们把
    "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文档, HashMap 类基本上等同于 Hashtable, 区别仅仅在于: HashMap 不是同步的,并且运行 null 值.
    5. LinkedHashMap
    LinkedHashMap 是 HashMap 的子类. 所以继承了所有 HashMap 的特性,另外, 链表保持了插入的顺序.
    我们复制上面的 HashMap 的示例代码,并将HashMap替换为LinkedHashMap:
    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<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输出的结果顺序与插入顺序是无关的. 
    下面再次列出使用 HashMap的输出结果以供对比:
    red dog – 10
    white dog – 20
    black dog – 15
    相关文章
    1. Java Convert Hashtable to Treemap
    2. Frequently Used Methods of Java HashMap
    3. Top 9 questions about Java Maps
    4. equals()与hashCode()方法协作约定

  • 相关阅读:
    配置centOS下的Python
    linux基础命令2
    linux基础命令1
    linux常用命令(运维用到)
    Lab 10-2
    Lab 10-1
    Lab 9-3
    archlinux 装完系统连接 wifi 网络
    arch Linux(二)
    arch Linux 安装完,无法通过 SSH 远程连接 root 用户问题
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467063.html
Copyright © 2011-2022 走看看