Map篇

一、Map接口

Map接口主要的方法有:

方法名 参数 返回类型 功能
size int 获取长度
isEmpty boolean 是否为空
containsKey boolean 是否包含 key
containsValue boolean 是否包含value
get K V 根据Key返回Value
put K,V V 存放键值对
remove K V 将key对应的键值对删除,并返回Value
putAll Map<? extends K,? extends V> 将另一个Map放入当前Map中
clear 清空
keySet Set<K> 返回Key的Set集合
values Collection<V> 返回Value的Collection集合
entrySet Set<Map.Entry<K, V>> 以Set的形式返回所有Entry
equals Object boolean 重写Object方法
hashCode int 重写Object方法

还有一些默认实现的方法:

方法名 参数 返回类型 功能
getOrDefault Object V default实现的方法,V为空且不包含当前key时,返回默认值
forEach BiConsumer<? super K, ? super V> void for循环执行BiConsumer的accept方法
replaceAll BiFunction<? super K, ? super V, ? extends V> function 通过BiFunction方法,接受K,V并返回新一个新的V,替换原来的Value
putIfAbsent K key, V value V 如果get(K)返回null,则执行put方法
remove K,V boolean 如果当前Value和传入Value相等,或当前Value不为null或包含当前Key,则执行remove(K)方法
replace K,OldV,NewV boolean 与上一方法雷同,只是最终执行put方法
replace K,V 当前有V或K存在时执行put
computeIfAbsent K,Function V 若当前V为null,则执行计算方法,put(K,NewV)
computeIfPresent K,BiFunction V 同上
compute K,BiFunction V 直接计算原K,V,替换V
merge K,V,BiFunction V 计算新老V,替换当前V

二、主要实现类

  1. HashMap
  2. HashTable
  3. ConcurrentHashMap

HashMap的实现

Java 7 中:
HashMap主要以数组的形式存放Entry,每个Entry是一个单向链表结构,存储了下一个键值对Entry<K,V> next,HashMap有几个重要的属性:

  1. capacity 容量
  2. loadFactor 负载因子
  3. threshold 扩容阀值

这几个属性涉及到了HashMap的扩容操作,即loadFactor为基本的负载因子,loadFactor*capacity=threshold,即当size>=threshoold,或者size/capacity>=loadFactory,且数组每个槽都至少有一个Entry的时候,HashMap会进行扩容操作。

Java 8 中:
HashMap除了以数组、链表的形式存储数据外,还以红黑树的形式对列表进行了优化。
以下是几个重要的参数:

字段 类型 默认值 释义
DEFAULT_INITIAL_CAPACITY int 16 默认的初始大小
MAXIMUM_CAPACITY int 1<<30 最大容量
DEFAULT_LOAD_FACTOR float 0.75f 默认负载因子
TREEIFY_THRESHOLD int 8 单链表转换为红黑树的阀值
UNTREEIFY_THRESHOLD int 6 红黑树还原为单链表的阀值
MIN_TREEIFY_CAPACITY int 64 最小转换为红黑树的阀值,这里需要说明:只有当容量超过这个阀值的时候,且满足红黑树转化繁殖,才会将链表转为红黑树,否则只会进行扩容操作。所以由以上默认值可知,只有当HashMap容量为128以上,扩容阀值在96以上时,才会有红黑树出现。

执行put操作的时候,流程图如下图所示:

20161126224434590 .jpg

Q1:什么是红黑树?
答:http://www.jianshu.com/p/b71eab42db06

Q2:HashMap如何实现红黑树的?
答:通过TreeNode

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    TreeNode<K,V> parent;  // red-black tree links
    TreeNode<K,V> left;
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    boolean red;
}
//同时,由于LinkedHashMap.Entry<K,V>继承了Node<K,V>,所以TreeNode还具有以下属性
    final int hash;
    final K key;
    V value;
    Node<K,V> next;

Q3:HashMap的扩容过程是怎样的?
答:

HashTable 的线程安全

HashTable使用数组加链表的方式实现,与HashMap 1.7中的实现十分类似,但通过同步锁,牺牲性能,实现了线程安全,如putfangfa :

 public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }

        addEntry(hash, key, value, index);
        return null;
    }

ConcurrentHashMap 的实现

Java 7 中:
以Segment的形式存储数据,相当于一个HashTable的数组,通过针对每个Segment上锁,实现了并发的写操作,默认数组大小为16,即理想状态下对HashTable的性能提升为16倍。

Java 8 中:
摒弃Segment的概念,改为以Node的节点的形式存储。
同时大量使用CAS来实现类似乐观锁的操作,保证线程安全。

Q2: ConcurrentHashMap操作的线程安全如何保证?
答:通过以下原子操作:

@SuppressWarnings("unchecked")
    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
    }

    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                        Node<K,V> c, Node<K,V> v) {
        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
    }

    static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
    }

参考链接:
http://blog.csdn.net/u011240877/article/details/53358305
http://www.jianshu.com/p/e694f1e868ec

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

推荐阅读更多精彩内容

  • java笔记第一天 == 和 equals ==比较的比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量...
    jmychou阅读 1,485评论 0 3
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,254评论 0 16
  • HashMap 是 Java 面试必考的知识点,面试官从这个小知识点就可以了解我们对 Java 基础的掌握程度。网...
    野狗子嗷嗷嗷阅读 6,657评论 9 107
  • Java SE 基础: 封装、继承、多态 封装: 概念:就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽...
    Jayden_Cao阅读 2,099评论 0 8
  • 妈妈很小的时候,外公就死了,妈妈跟着外婆和弟弟一起过日子。 一个没有男人操持的家,日子自然不好过。外婆实在没有办法...
    生活在绿野上阅读 180评论 0 1