常用Map实现类对比

简介: 翻译人员: 铁锚 翻译时间: 2013年12月12日 原文链接: HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap 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()方法协作约定

目录
相关文章
|
2月前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
61 3
|
4月前
|
Java
【Java集合类面试二十二】、Map和Set有什么区别?
该CSDN博客文章讨论了Map和Set的区别,但提供的内容摘要并未直接解释这两种集合类型的差异。通常,Map是一种键值对集合,提供通过键快速检索值的能力,而Set是一个不允许重复元素的集合。
|
4月前
|
JavaScript 前端开发
Vue 系类之 this.tabledatas.map 无效
这篇文章讲述了在Vue项目中使用`this.tabledatas.map`处理接口返回的数组数据时遇到的问题,原因是由于取错了后端返回的数据集合字段值,导致`.map`方法无效,通过检查和修正数据取值解决了问题。
Vue 系类之 this.tabledatas.map 无效
|
4月前
|
算法 Java 索引
【Java集合类面试四】、 描述一下Map put的过程
这篇文章详细描述了HashMap中put操作的过程,包括首次扩容、计算索引、插入数据以及链表转红黑树和可能的再次扩容。
【Java集合类面试四】、 描述一下Map put的过程
|
4月前
|
安全 Java
【Java集合类面试五】、 如何得到一个线程安全的Map?
如何得到一个线程安全的Map的方法包括:使用Collections工具类将Map包装为线程安全,使用java.util.concurrent包下的ConcurrentHashMap,以及不推荐使用性能较差的Hashtable。
|
4月前
|
安全 Java
【Java集合类面试三】、Map接口有哪些实现类?
这篇文章介绍了Java中Map接口的几种常用实现类:HashMap、LinkedHashMap、TreeMap和ConcurrentHashMap,以及它们适用的不同场景和线程安全性。
|
6月前
|
存储 编译器 C++
|
6月前
|
程序员
Map.Entry 类使用简介
Map.Entry 类使用简介
50 1
|
6月前
|
消息中间件 Java 开发工具
消息队列 MQ产品使用合集之topic相同,但是tag不同,这个类不能放入map中,该如何处理
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
7月前
|
存储 Java
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法
【JAVA学习之路 | 进阶篇】Map接口及其实现类及常用方法