这些看完hashmap就差不多了
1、HashMap的底层数据结构?
jdk 1.8 数组+链表+红黑树 jdk 1.7 数组+链表 学院派经典的写法
2、HashMap的存取原理?
初始化:hashmap的node[]是null put方法初始化node[] 默认长度16,负载因子0.75 hashtable在创建时初始化,默认长度11 负载因子0.75 取数据:首先要判断node数组是否为null或者是空,如若是返回null,否则检查改下标的第一个节点(设计初衷是让数据均匀分散,直接查出数据的可能性比较大,因此总是检查第一个),如果没查出来,就判断该下标的数组元素是否为红黑树,是则通过getTreeNode查找,否则循环链表查找,如果都没找到,返回null 存数据:判断node数组元素是否能放数据,不能就初始化,,节点为空直接放node,否则判断是否为红黑树,如果是,就通过value和hash值比较,没有相同的就添加,有相同的的的修改, 如果不是树添加到链表中,添加是要判断值和哈希值是否相同,判断链表长度是否需要树化,将新的节点添加或者value更新到map中,判断map大小超过阈值就扩容。尾插法实现
hashtable存取原理
存数据:首先判断容器的table是否为null,如果为null初始化table hashtable:先判断key是否为空抛空指针异常,检查key是否存在,存在则找到entry替换value 否则调用addEntry方法添加entry,是否需要扩容,rehash左移加一位加一,hash重排序。hash值和0x7FFFFFFF位于取数组长度的模,添加新元素 取数据:计算下标,到对应位置,为空则返回null否则根据key和hash获取value。
3、Java7和Java8的区别?
区别:数据结构不同,8 修改了hashmap的实现方式,增加了红黑树的结构,提高了查询效率,时间复杂度从O(n)降低到了O(log n)。 java 7 使用头插法,这个方法在多线程的情况下会产生死循环,存在 java 8 使用尾插法多线程也是不安的,a线程存1,b线程删除,a线程就找不到1了。
4、为啥会线程不安全?
见3
5、有什么线程安全的类代替么?
currenthashmap
6、默认初始化大小是多少?为啥是这么16而不是8或32?为什么选择2的幂作为容量大小?为啥大小都是2的幂?
初始大小是16, 如果分配8或4将导致map扩容影响性能,分配32会使得map占用空间增大,浪费资源,16应该是最佳实践结果。 这与hashmap的哈希值计算有关,hashMap计算添加元素的位置时,使用位运算(高效),使得散列更加充分(减少hash碰撞) 因为put()数据初始化容量时会做判断,如果不是2的幂,会调用Integer中的 heighestOneBit()方法强行修改为2的幂。2的幂是为了保证计算下标的效率,hashmap中是通过容量-1计算下标值。
7、HashMap的扩容方式?负载因子是多少?为什是这么多?
hashcode和桶按位与就是index 超过阈值双倍扩容,负载因子0.75 HashMap作为一种数据结构,首要考虑节省时间空间,负载因子设置0.75的情况下,空间利用率较高的同时,避免了一定量 resize的效率很低所以如果数值太大的话就要设定初始容量。
8、 HashMap的主要参数都有哪些?
负载因子、初始容量、最大容量 链表转红黑树阈值8(树化阈值)桶中节点分布服从泊松分布超过8概率会很小 红黑树转链表阈值6(链化阈值)红黑树转换条件数组长度为64
9、 HashMap是怎么处理hash碰撞的?
通过链表和红黑树的方式,发生哈希碰撞后判断键是否相同,如果相同则替换v,如果不同,首先判定数据是否满足负载因子,不满足则重排序,满足判断数组存放的数据结构是链表还是红黑树,如果是链表,则判断链表长度如果长度是否为8数组长度是否为64,是则转换成红黑树机构存放,否则扩展数组存放
10、 hash的计算规则?
Asicll码相加得知取模 如果key是null,哈希值为0,如果不是null,则通过key的hash方法计算出一个值,将该值的高低十六位做异或(不进位的加法)运算,得到hashcode值。
11、Java7的缺陷
1:并发环境容易碰到死锁。成环不一定死锁,用到时产生。 2:可以通过精心构造的恶意请求引发Dos 链表性能退化 ;tomcat限制参数长度。
肝了两天,小姐姐聊天都没理,看源码、视频和博客的成果,XDM给个三连呗(O.O)