JAVA学习-Map详解

1.介绍

Map接口定义了一个保存key-value的对象,该对象中key值是不存在重复的,每个key值至多对应一个value
在前面几篇的文章中分别介绍了Map的实现类,如HashMap、Hashtable、TreeMap,详细可以查看

2.类图结构

Map结构

如上图所示是实现Map接口的类图结构,主要包含了如下的类与接口:

  • Map接口: 定义将键值映射到值的对象,Map规定不能包含重复的键值,每个键最多可以映射一个值,这个接口是用来替换Dictionary类。
  • SortedMap接口:定义按照key排序的Map结构,规定key-value是根据键key值的自然排序进行排序的,或者根据构造key-value时设定的构造器进行排序。
  • NavigableMap接口: 是SortedMap接口的子接口,在其基础上扩展了针对搜索目标返回最近匹配项的导航方法,例如方法lowEntry、floorEntry、ceilingEntry等,如果不存在这样的键,则返回null
  • AbstractMap类:提供了一个Map骨架的实现,尽量减少了实现Map接口所需要的工作量
  • HashMap类:HashMap是实现了Map接口的key-value集合,实现了所有map的操作,允许key和value为null,它相当于Hashtable,与之存在的区别是hashMap不是线程安全的,HashMap允许null值。
  • TreeMap类:TreeMap是基于红黑树的实现,也是记录了key-value的映射关系,该映射根据key的自然排序进行排序或者根据构造方法中传入的比较器进行排序,也就是说TreeMap是有序的key-value集合
  • Hashtable类:它是类似与HashMap的key-value的哈希表,不允许key-value为NULL值,另外一点值得注意的是Hashtable是线程安全的
  • Serializable接口:实现了该接口标识了类可以被序列化和反序列化,具体的 查询序列化详解
  • Cloneable接口:实现了该接口的类可以显示的调用Object.clone()方法,合法的对该类实例进行字段复制,如果没有实现Cloneable接口的实例上调用Obejct.clone()方法,会抛出CloneNotSupportException异常。正常情况下,实现了Cloneable接口的类会以公共方法重写Object.clone()

3.比较

虽然HashMap、Hashtable、TreeMap这三个都是Map接口的实现,其内部实现及性能等还是存在区别,下面将从区别及性能两个方面去分析。

3.1 区别

3.1.1 基本
  • HashMap:初始化容量为16,扩容每次为2*oldCap,key-value可以为NULL值
  • Hashtable:初始化容量为11,扩容每次为2*oldCap+1,key-value不可以为NULL值
  • TreeMap:初始化容量为0,内部是红黑树结构,不存在hash冲突的情况,不存在扩容的操作,key-value不可以为NULL值
3.1.2 实现
  • HashMap:实现了Map接口,继承了AbstractMap类
  • Hashtable:实现了Map接口,继承了AbstractMap类
  • TreeMap:由于TreeMap是有序的,所以其除了实现了Map接口,还实现了SortedMap、NavigableMap接口
3.1.3 内部原理
  • HashMap:HashMap是散列表实现,内部是数组+链表或者红黑树的结构
  • Hashtable:Hashtable也是散列表实现,内部是数组+链表的结构
  • TreeMap:TreeMap内部是红黑树的结构
3.1.4 线程安全
  • HashMap:不是线程安全的,其实通过Map m = Collections.synchronizeMap(hashMap)的方式也可以使得HashMap变成线程安全的,但是这样做对程序的性能可能是噩梦,在后面会介绍ConcurrentHashMap,建议在多线程的情况下可以使用ConcurrentHashMap替换HashMap.
  • Hashtable:是线程安全的,内部方法使用关键字synchronized修饰
  • TreeMap:不是线程安全的

3.2 性能

按照如下代码对HashMap、Hashtable、TreeMap的性能进行测试

public class HashMapProgress {
    //定义用于测试的HashMap
    private static HashMap<Integer,Integer> hashMap = new HashMap<>();
    //定义用于测试的Hashtable
    private static Hashtable<Integer,Integer> hashtable = new Hashtable<>();
    //定义用于测试的TreeMap
    private static TreeMap<Integer,Integer> treeMap = new TreeMap<>();

    /**
     * 添加元素的方法
     * @param map 对应的map
     * @param count 添加个数
     */
    public static void addEntry(Map<Integer,Integer> map, int count){
        Long startTime = System.currentTimeMillis();
        if (count <= 0){
            return;
        }
        for (int i = 0; i < count; i++) {
            map.put(i,i);
        }
        Long endTime = System.currentTimeMillis();
        System.out.println("添加(" + count + ")个元素使用时间:" + (endTime - startTime) + "s");
    }

    /**
     * 获取元素的方法
     * @param map
     * @param count
     */
    public static void getEntry(Map<Integer,Integer> map, int count){
        Long startTime = System.currentTimeMillis();
        if (count <= 0){
            return;
        }
        for (int i = 0; i < count; i++) {
            map.get(i);
        }
        Long endTime = System.currentTimeMillis();
        System.out.println("获取(" + count + ")个元素使用时间:" + (endTime - startTime) + "s");
    }

    public static void main(String[] args){
        System.out.println("-------HashMap测试开始-----");
        addEntry(hashMap,1000000);
        getEntry(hashMap,1000000);
        System.out.println("-------HashMap测试结束-----");

        System.out.println("-------Hashtable测试开始-----");
        addEntry(hashtable,1000000);
        getEntry(hashtable,1000000);
        System.out.println("-------Hashtable测试结束-----");

        System.out.println("-------TreeMap测试开始-----");
        addEntry(treeMap,1000000);
        getEntry(treeMap,1000000);
        System.out.println("-------TreeMap测试结束-----");
    }
}

分别测试了100000,1000000,10000000个数据的情况,测试结果如下所示:

数据量 HashMap Hashtable TreeMap
100000 插入用时:18s 查询用时:9s 插入用时:14s 查询用时:5s 插入用时:33s 查询用时:17s
1000000 插入用时:98s 查询用时:20s 插入用时:625s 查询用时:31s 插入用时:242s 查询用时: 145s
10000000 插入用时:9773s 查询用时:811s 插入用时:15055s 查询用时:3369s 插入用时:22354s 查询用时: 3889s

通过上表可以看出随着数据量的增加,时间变化差异还是很大的,而在单线程的情况下还是尽量使用HashMap,相对于Hashtable、TreeMap性能更好,而针对特定的情况需视情况而论。

4.总结

本文主要是对前面介绍的HashMap、Hashtable、TreeMap这些Map接口实现类的一个总结,主要分析这些实现类的一些特点以及存在的差异,最后想说的是针对不同的情况可以选择不同的Map进行编码,如有问题,望指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,213评论 0 16
  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,440评论 0 3
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,015评论 11 349
  • “天真岁月不忍欺,青春荒唐我不负你”很喜欢《时间煮雨》这首歌中的这句话,我最爱的你们还记得吗?曾经我们也说好要一直...
    蕊汐阅读 422评论 0 0