• hashMap记录


    继承了abstractMap, 实现了map、cloneable、serializable接口

    初始参数

    默认初始化容量16

    最大容量1<<30(约10亿)

    默认负载因子0.75

    阈值为容量*负载因子

    结构被修改次数modCount(修改val不算)

    构造函数

    hashMap(初始容量,负载因子)

    hashMap(初始容量):加上默认负载因子

    hashMap(): 默认初始容量,默认负载因子

    hashMap(Map): 新建一个hashMap, 容量为(传入的map的容量/负载因子 + 1)和默认容量的最大值,并用map的元素填充新hashMap

    方法

    hash(h):静态,默认访问权限。
    这个有点儿复杂,只是记下h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);

    indexFor(h, length): 静态,默认访问权限。
    h&(length-1) 这里可以看出容量选择2的幂的原因了:lenght-1之后二进制所有位都是1(除最高位以上),进而有快速屏蔽h高位的效果

    get(key): 对于key为null,直接查找table数组的第一位(下标为0);非null的键,先hash出在table数组中的下标,再检索Entry链表

    put(key, value): 对于key为null,放到table数组的第一个。非null的key,若存在,更新val,返回原始值;不存在则新建entry,将table原来该位置的entry链放到新entry的后边(即头插法,听说jdk8采用尾插法)。元素个数大于阈值,resize扩大一倍长度

    resize(newCapacity): 默认访问权限。
    如果容量已经是最大容量则该阈值为Integer最大值,不再扩容。否则,创建新数组,将原来的元素rehash放入数组。
    这里会有一个问题(面试官会考的哦),就是链表会出现无线循环。问题出在这行代码 e.next = newTable[i];上,e结点位于原数组上的一条链表,newTable[i]是对应的扩容后的新数组上的链表(对应的新链表)的头结点(随着扩容的进行,原链表的元素从头到尾,往新链表的头部进行插入)。

    当两个线程同时进行resize的时候就存在这样一种情况:e.next = e(死循环),也就是newTable[i]=e了。为什么会出现这种情况呢? 想象一下只有一个线程的情况,代码执行到下一行才会将e赋值给newTable[i], 也就是newTable[i]指向了已e开头的新链表。也就不会存在e=e的情况。
    为啥多线程就会有问题了呢?就是因为存在另一个线程会在当前线程准备执行e.next = newTable[i]的时候,提前执行了newTable[i]=e。所以就有了死循环。

    remove(key):根据键删除有键值的Entry对象。

    clear(): table数组的每一项都置为null。modCount加1。

    containsValue(value):map是否包含value值对应的键值对。分为null和非null的查找。

    clone(): 对当前hashMap浅拷贝,key和value不会被拷贝。

    keySet(): 返回key的set集合。

    values(): 返回value的集合。

    entrySet(): 返回Entry的集合。

    内部类

    Entry: 保存key、value的对象,实现了hashCode()、equal()、toString()方法。

    hashIterator: 迭代器。及其子类ValueIterator、KeyIterator、EntryIterator,只了重写next方法。

    keySet: 继承abstractSet,为keyset()方法服务。

    Values: 继承了abstractCollection, 为values()方法服务。

    EntrySet: 继承了abstractSet, 为entrySet()方法服务。

    相关类

    一些继承或者相关的类

    LinkedHashMap

    继承了hashMap。在内部维护了一个双向链表,在新增或删除元素的时候,对双向链表进行维护。具体的存储查找删除元素还是hashmap的逻辑,在遍历map的时候用的是双向链表,不会遍历没有hash到的位置,所以更高效。再有就是新map提供遍历顺序是插入顺序还是访问顺序。

  • 相关阅读:
    redolog switch会发生完全检查点还是增量检查点?
    4G牌照发放生变 专家谏言电信联通如何选择
    [财富]iPhone如何征服日本?
    审计中移动现多处问题或致地方高层落马
    诺基亚CEO:Lumia不会像安卓推廉价版机型
    菜鸟学JDBC(二)
    简易网页采集器的实现
    手Q与微信:最终结局将会是手足相残!
    做网站Http状态码详解
    PHP $_SERVER['HTTP_REFERER'] 获取前一页面的 URL 地址
  • 原文地址:https://www.cnblogs.com/so-easy/p/12159621.html
Copyright © 2020-2023  润新知