zoukankan      html  css  js  c++  java
  • hashMap

    1 hashmap的数据结构是什么样子的?

    jdk 1.8 新加的内容

    • 当链表长度大于8之后(在数组长度大于64的前提下),链表就会转换为红黑树了。

    2 put方法怎么实现的?

    3 扩容机制是什么?【jdk 1.7的代码,1.8的加入了红黑树,代码比较难看】

     

    4 为什么扩容大小为2的幂次方?

    查找快:将Key值进行Hash后得到Hash值,Hash值得范围大概40亿,很明显,内存存不下,进行转换,对数组的长度(即hashmap的长度)进行取模运算,得到的余数才用来做要存放的位置(即对应的数组下标)。[这也解释了HashMap的长度为什么是2的幂次方,为了提高取模运算的效率]。

    分散均匀:

    HashMap 采用这种非常规设计,主要是为了在取模和扩容时做优化,同时为了减少hash碰撞,HashMap 定位哈希桶索引位置时,也加入了高位参与运算的过程。

    长度16或者其他2的幂,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的。

    如果不为16或者2的幂,那么,经过hash算法之后,有些index结果出现的概率会更大,而有些index则永远步会出现。即不符合hash算法的j均匀分布的原则。

    5 什么是负载因子,为什么默认值是0.75?

    负载因子表示的是一个散列表的空间使用程度。

    源码里对负载因子有一段解释,大概意思就是:在理想情况下,使用随机哈希吗,节点出现的频率在hash桶中遵循泊松分布,同时给出了桶中元素的个数和概率的对照表。

    从上表可以看出当桶中元素到达8个的时候,概率已经变得非常小,也就是说用0.75作为负载因子,每个碰撞位置的链表长度超过8个是几乎不可能的。
    hash容器指定初始容量尽量为2的幂次方。
    HashMap负载因子为0.75是空间和时间成本的一种折中。

    6 如何解决 hash 冲突的?

    拉链法

    7 是不是线程安全的?

    • HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。
    • 补充一点 Hashtable 是线程安全的。还有并发的 HashMap :ConcurrentHashMap(java5引入的)。

    8 hashmap 与 hashtable 的与别是什么?

    1. HashMap线程不安全,是非synchronized的,Hashtable是线程安全的。

    2. HashMap可以接受null(HashMap可以接受为null的键值(key)和值(value)),而Hashtable则不行。

    3. 是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。

    4. 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

    5. HashMap不能保证随着时间的推移Map中的元素次序是不变的。

    6. 继承的父类不同、作者不同,产生时间不同。HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了Map、Cloneable(可复制)、Serializable(可序列化)这三个接口

    7. 初始容量大小和每次扩充容量大小的不同。Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。

    8. 计算hash值的方法不同。为了得到元素的位置,首先需要根据元素的Key计算出一个hash值,然后再用这个hash值来计算得到最终的位置。Hashtable直接使用对象的hashCode。然后再使用取余来获得最终的位置,比较耗时。HashMap是通过位运算来进行操作的,效率高。
    下面是 Hashtable 的确定索引方法:
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;

    9 为什么不一下子把链表转化成红黑树?

    1. 构造红黑树要比构造链表复杂,在链表的节点不多的时候,从整体的性能看来, 数组+链表+红黑树的结构可能不一定比数组+链表的结构性能高。

    2. HashMap 频繁的扩容,会造成底部红黑树不断的进行拆分和重组,这是非常耗时的。因此,也就是链表长度比较长的时候转变成红黑树才会显著提高效率。

  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/junbaba/p/12956634.html
Copyright © 2011-2022 走看看