常用Map实现类对比
翻译人员: 铁锚
翻译时间: 2013年12月12日
原文链接: HashMap
vs. TreeMap vs. Hashtable vs. LinkedHashMap
Map 是最常用的数据结构之一.
Map 的字面翻译是映射(地图就是一种映射).
本文将为你展示如何使用各种不同的map,包括 HashMap, TreeMap, HashTable 以及 LinkedHashMap.
1. Map 概述
在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
相关文章:
- Java
Convert Hashtable to Treemap - Frequently
Used Methods of Java HashMap - Top
9 questions about Java Maps - equals()与hashCode()方法协作约定
常用Map实现类对比的更多相关文章
- Java开发常用Util工具类-StringUtil、CastUtil、CollectionUtil、ArrayUtil、PropsUtil
字符串工具类 StringUtil.java package com.***.util; /** * StringUtil * @description: 字符串工具类 **/ public clas ...
- Android常用的工具类
主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java.目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils. Prefe ...
- Android常用的工具类(转)
主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java.目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils.Prefer ...
- list 、set 、map 粗浅性能对比分析
list .set .map 粗浅性能对比分析 不知道有多少同学和我一样,工作五年了还没有仔细看过list.set的源码,一直停留在老师教导的:"LinkedList插入性能比Array ...
- 2013最新Android常用的工具类整理
主要介绍总结的Android开发中常用的工具类,大部分同样适用于Java. 目前包括HttpUtils.DownloadManagerPro.ShellUtils.PackageUtils. Pref ...
- Java并发包——线程安全的Map相关类
Java并发包——线程安全的Map相关类 摘要:本文主要学习了Java并发包下线程安全的Map相关的类. 部分内容来自以下博客: https://blog.csdn.net/bill_xiang_/a ...
- commons-collections包中的常用的工具类
commons-collections包中的常用的工具类 <dependency> <groupId>commons-collections</groupId> & ...
- Hutool中那些常用的工具类和方法
Hutool中那些常用的工具类和方法 Hutool是一个Java工具包,它帮助我们简化每一行代码,避免重复造轮子.如果你有需要用到某些工具方法的时候,不妨在Hutool里面找找,可能就有.本文将对Hu ...
- DBUtils ResultSetHandeler常用的处理类
常用的处理类: BeanHandler: //将结果集中第一条记录封装到一个指定的javaBean中 BeanListHandler: //将结果集中每一条记录封装到指定的javaBean中,将这些j ...
随机推荐
- U盘PE无人值守安装centOS6
一.制作 1.需要用到的工具:老毛桃PX工具.系统ISO.一个8GU盘 老毛桃PE工具 http://laomaotao.net/ CentOS启动映像 http://mirrors.163.com/ ...
- ELK学习记录一 :初识ELK
ELK是elastic公司提供的一套完整的收集日志并分析展示的产品,分别表示Elasticsearch.Logstash和kibana. (官网截个图) 先来一段个人粗浅的认识: Elasticsea ...
- 论文答辩ppt要怎么写
1.总体原则: 字大.字少.图多.要有重点 字体建议:正文要用黑体(如微软雅黑),标题可使用宋体或者黑体(如微软雅黑) 2. 主要分为两大部分: 2.1系统介绍 系统概述:概述自己系统主要是做了些什么 ...
- 预处理指令--C语言
ANSI标准C还定义了如下几个宏: __LINE__ 表示正在编译的文件的行号 __FILE__ 表示正在编译的文件的名字 __DATE__ 表示编译时刻的日期字符串,例如:"25 Dec ...
- Programming In Scala笔记-第十一章、Scala中的类继承关系
本章主要从整体层面了解Scala中的类层级关系. 一.Scala的类层级 在Java中Object类是所有类的最终父类,其他所有类都直接或间接的继承了Object类.在Scala中所有类的最终父类为A ...
- Swift运行时简介
因为Swift的操作在高层并且也得与Objc联合起来干活,用Swift写的程序一般会被Objc和Swift运行时处理.因为Swift的本性--换句话说,它是一门静态语言--Swift运行时在一些关键地 ...
- Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava
Retrofit2.0通俗易懂的学习姿势,Retrofit2.0 + OkHttp3 + Gson + RxJava Retrofit,因为其简单与出色的性能,也是受到很多人的青睐,但是他和以往的通信 ...
- Java多线程的调度策略
在Java多线程环境中,为保证所有线程的执行能按照一定的规则执行,JVM实现了一个线程调度器,它定义了线程调度的策略,对于CPU运算的分配都进行了规定,按照这些特定的机制为多个线程分配CPU的使用权. ...
- Spark分布式计算和RDD模型研究
1背景介绍 现今分布式计算框架像MapReduce和Dryad都提供了高层次的原语,使用户不用操心任务分发和错误容忍,非常容易地编写出并行计算程序.然而这些框架都缺乏对分布式内存的抽象和支持,使其在某 ...
- iOS10软件崩溃 Xcode8崩溃 打印/字体等问题汇总 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博!iOS开发者交流QQ群: 446310206 [1].Xcode8代码出现ubsystem: com.apple.U ...