@@ -580,29 +580,31 @@ public class Test1 {
580580 * 负数:
581581 原码:最高位为1,其余位置和正数相同
582582 反码:保证符号位不变,其余位置取反
583- 补码:保证符号位不变,其余位置取反加1 ,即反码+1
583+ 补码:保证符号位不变,其余位置取反加 1 ,即反码 +1
584584
585585 ```java
586586 -100原码: 10000000 00000000 00000000 01100100 //32位
587587 -100反码: 11111111 11111111 11111111 10011011
588588 -100补码: 11111111 11111111 11111111 10011100
589589 ```
590590
591- 补码 → 原码:符号位不变,其余位置取反加1
591+ 补码 → 原码:符号位不变,其余位置取反加 1
592592
593593 运算符:
594594
595595 * `>>` 运算符:将二进制位进行右移操作,相当于除 2
596596 * `<<` 运算符:将二进制位进行左移操作,相当于乘 2
597- * `>>>` 运算符:无符号右移,忽略符号位,空位都以0补齐
597+ * `>>>` 运算符:无符号右移,忽略符号位,空位都以 0 补齐
598598
599599 运算规则:
600600
601- * 正数的左移与右移,空位补0
602- * 负数原码的左移与右移,空位补0
603- 负数反码的左移与右移,空位补1
604- 负数补码,左移低位补0,右移高位补1
605- * 无符号移位,空位补0
601+ * 正数的左移与右移,空位补 0
602+ * 负数原码的左移与右移,空位补 0
603+
604+ 负数反码的左移与右移,空位补 1
605+
606+ 负数补码,左移低位补 0(会导致负数变为正数的问题,因为移动了符号位),右移高位补 1
607+ * 无符号移位,空位补 0
606608
607609
608610
@@ -4598,8 +4600,8 @@ HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存
45984600* HashMap的实现不是同步的,这意味着它不是线程安全的
45994601* key 是唯一不重复的,底层的哈希表结构,依赖 hashCode 方法和 equals 方法保证键的唯一
46004602* key、value 都可以为null,但是 key 位置只能是一个null
4601- * HashMap中的映射不是有序的 ,即存取是无序的
4602- * **key要存储的是自定义对象,需要重写hashCode和equals方法,防止出现地址不同内容相同的key **
4603+ * HashMap 中的映射不是有序的 ,即存取是无序的
4604+ * **key 要存储的是自定义对象,需要重写 hashCode 和 equals 方法,防止出现地址不同内容相同的 key **
46034605
46044606JDK7 对比 JDK8:
46054607
@@ -4612,10 +4614,10 @@ JDK7 对比 JDK8:
46124614
46134615* 哈希表(Hash table,也叫散列表),根据关键码值(Key value)而直接访问的数据结构。通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表
46144616
4615- * JDK1.8 之前 HashMap 由 ** 数组+链表** 组成
4617+ * JDK1.8 之前 HashMap 由 数组+链表 组成
46164618
46174619 * 数组是 HashMap 的主体
4618- * 链表则是为了**解决哈希冲突**而存在的 (**拉链法**解决冲突 ),拉链法就是头插法
4620+ * 链表则是为了解决哈希冲突而存在的 (**拉链法解决冲突** ),拉链法就是头插法
46194621 两个对象调用的hashCode方法计算的哈希码值(键的哈希)一致导致计算的数组索引值相同
46204622
46214623* JDK1.8 以后 HashMap 由 **数组+链表 +红黑树**数据结构组成
@@ -4686,7 +4688,7 @@ HashMap继承关系如下图所示:
46864688
46874689 * 如果输入值不是2的幂会怎么样?
46884690
4689- 创建HashMap对象时,HashMap通过位移运算和或运算得到的肯定是2的幂次数 ,并且是大于那个数的最近的数字,底层采用tableSizeFor() 方法
4691+ 创建 HashMap 对象时,HashMap 通过位移运算和或运算得到的肯定是 2 的幂次数 ,并且是大于那个数的最近的数字,底层采用 tableSizeFor() 方法
46904692
469146933. 默认的负载因子,默认值是 0.75
46924694
@@ -4698,15 +4700,15 @@ HashMap继承关系如下图所示:
46984700
46994701 ```java
47004702 //集合最大容量的上限是:2的30次幂
4701- static final int MAXIMUM_CAPACITY = 1 << 30;
4703+ static final int MAXIMUM_CAPACITY = 1 << 30;// 0100 0000 0000 0000 0000 0000 0000 0000 = 2 ^ 30
47024704 ```
47034705
47044706 最大容量为什么是 2 的 30 次方原因:
47054707
47064708 * int 类型是 32 位整型,占 4 个字节
4707- * Java 的原始类型里没有无符号类型,所以首位是符号位正数为 0,负数为 1
4709+ * Java 的原始类型里没有无符号类型,所以首位是符号位正数为 0,负数为 1,
47084710
4709- 5. 当链表的值超过8则会转红黑树(1.8新增** )
4711+ 5. 当链表的值超过 8 则会转红黑树(JDK1.8 新增 )
47104712
47114713 ```java
47124714 //当桶(bucket)上的结点数大于这个值时会转成红黑树
@@ -4735,7 +4737,7 @@ HashMap继承关系如下图所示:
47354737 * 其他说法
47364738 红黑树的平均查找长度是 log(n),如果长度为 8,平均查找长度为 log(8)=3,链表的平均查找长度为 n/2,当长度为 8 时,平均查找长度为 8/2=4,这才有转换成树的必要;链表长度如果是小于等于 6,6/2=3,而 log(6)=2.6,虽然速度也很快的,但转化为树结构和生成树的时间并不短
47374739
4738- 6. 当链表的值小 于6 则会从红黑树转回链表
4740+ 6. 当链表的值小 于 6 则会从红黑树转回链表
47394741
47404742 ```java
47414743 //当桶(bucket)上的结点数小于这个值时树转链表
@@ -4749,16 +4751,16 @@ HashMap继承关系如下图所示:
47494751 static final int MIN_TREEIFY_CAPACITY = 64;
47504752 ```
47514753
4752- 原因:数组比较小的情况下变为红黑树结构,反而会降低效率,红黑树需要进行左旋,右旋,变色这些操作来保持平衡。同时数组长度小于64时 ,搜索时间相对快些,所以为了提高性能和减少搜索时间,底层在阈值大于8并且数组长度大于64时 ,链表才转换为红黑树,效率也变的更高效
4754+ 原因:数组比较小的情况下变为红黑树结构,反而会降低效率,红黑树需要进行左旋,右旋,变色这些操作来保持平衡。同时数组长度小于 64 时 ,搜索时间相对快些,所以为了提高性能和减少搜索时间,底层在阈值大于 8 并且数组长度大于 64 时 ,链表才转换为红黑树,效率也变的更高效
47534755
4754- 8. table用来初始化( 必须是二的n次幂)(重点)
4756+ 8. table 用来初始化( 必须是二的n次幂)
47554757
47564758 ```java
47574759 //存储元素的数组
47584760 transient Node<K,V>[] table;
47594761 ```
47604762
4761- jdk8之前数组类型是Entry <K,V>类型,从jdk1.8之后是Node <K,V>类型。只是换了个名字,都实现了一样的接口: Map.Entry<K,V>,负责存储键值对数据的
4763+ jdk8 之前数组类型是 Entry <K,V>类型,之后是 Node <K,V> 类型。只是换了个名字,都实现了一样的接口 Map.Entry<K,V>,负责存储键值对数据的
47624764
47634765 9. HashMap中存放元素的个数(**重点**)
47644766
@@ -4797,11 +4799,11 @@ HashMap继承关系如下图所示:
47974799 HashMap(int initialCapacity, float loadFactor)//构造指定初始容量和加载因子的空HashMap
47984800 ```
47994801
4800- * 为什么加载因子设置为0 .75,初始化临界值是12 ?
4802+ * 为什么加载因子设置为 0 .75,初始化临界值是 12 ?
48014803
4802- loadFactor太大导致查找元素效率低 ,存放的数据拥挤,太小导致数组的利用率低,存放的数据会很分散。loadFactor的默认值为 **0.75f是官方给出的一个比较好的临界值**。
4804+ loadFactor 太大导致查找元素效率低 ,存放的数据拥挤,太小导致数组的利用率低,存放的数据会很分散。loadFactor 的默认值为 **0.75f 是官方给出的一个比较好的临界值**
48034805
4804- * ** threshold** 计算公式:capacity(数组长度默认16) * loadFactor(负载因子默认0 .75)。这个值是当前已占用数组长度的最大值。**当Size >=threshold**的时候,那么就要考虑对数组的resize (扩容),这就是 **衡量数组是否需要扩增的一个标准** , 扩容后的 HashMap 容量是之前容量的**两倍**.
4806+ * threshold 计算公式:capacity(数组长度默认16) * loadFactor(负载因子默认 0 .75)。这个值是当前已占用数组长度的最大值。**当 size >=threshold** 的时候,那么就要考虑对数组的 resize (扩容),这就是衡量数组是否需要扩增的一个标准 , 扩容后的 HashMap 容量是之前容量的**两倍**.
48054807
48064808
48074809
@@ -4903,7 +4905,7 @@ HashMap继承关系如下图所示:
49034905
490449061. hash
49054907
4906- HashMap是支持Key为空的;HashTable是直接用Key来获取HashCode,key为空会抛异常
4908+ HashMap 是支持 Key 为空的;HashTable 是直接用 Key 来获取 HashCode,key 为空会抛异常
49074909
49084910 * &(按位与运算):相同的二进制数位上,都是1的时候,结果为1,否则为零
49094911 * ^(按位异或运算):相同的二进制数位上,数字相同,结果为0,不同为1,**不进位加法**
@@ -4917,13 +4919,13 @@ HashMap继承关系如下图所示:
49174919 }
49184920 ```
49194921
4920- 计算 hash 的方法:将hashCode无符号右移16位,高16bit 和低16bit 做了一个异或
4922+ 计算 hash 的方法:将 hashCode 无符号右移 16 位,高 16bit 和低 16bit 做了一个异或,扰动运算
49214923
4922- 原因:当数组长度很小,假设是16 ,那么 n-1即为 1111 ,这样的值和hashCode() 直接做按位与操作,实际上只使用了哈希值的后4位。如果当哈希值的高位变化很大,低位变化很小,就很容易造成哈希冲突了,所以这里**把高低位都利用起来,让高16位也参与运算 **,从而解决了这个问题
4924+ 原因:当数组长度很小,假设是 16 ,那么 n-1即为 1111 ,这样的值和 hashCode() 直接做按位与操作,实际上只使用了哈希值的后4位。如果当哈希值的高位变化很大,低位变化很小,就很容易造成哈希冲突了,所以这里**把高低位都利用起来,让高16 位也参与运算 **,从而解决了这个问题
49234925
49244926 哈希冲突的处理方式:
49254927
4926- * 开放定址法:线性探查法(ThreadLocalMap部分详解 ),平方探查法(i + 1^2、i - 1^2、i + 2^2……)、双重散列(多个哈希函数)
4928+ * 开放定址法:线性探查法(ThreadLocalMap 使用 ),平方探查法(i + 1^2、i - 1^2、i + 2^2……)、双重散列(多个哈希函数)
49274929 * 链地址法:拉链法
49284930
49294931
@@ -5015,7 +5017,7 @@ HashMap继承关系如下图所示:
50155017 1. `int n = cap - 1`:防止 cap 已经是 2 的幂。如果 cap 已经是 2 的幂, 不执行减 1 操作,则执行完后面的无符号右移操作之后,返回的 capacity 将是这个 cap 的 2 倍
50165018 2. n=0 (cap-1 之后),则经过后面的几次无符号右移依然是 0,返回的 capacity 是 1,最后有 n+1
50175019 3. |(按位或运算):相同的二进制数位上,都是 0 的时候,结果为 0,否则为 1
5018- 4. 核心思想:把最高位是 1 的位以及右边的位全部置 1,结果加 1 后就是最小的2的 n 次幂
5020+ 4. 核心思想:** 把最高位是 1 的位以及右边的位全部置 1** ,结果加 1 后就是最小的2的 n 次幂
50195021
50205022 例如初始化的值为 10:
50215023
@@ -9904,7 +9906,7 @@ public class Demo1_8 extends ClassLoader { // 可以用来加载类的二进制
99049906
99059907#### 直接内存
99069908
9907- 直接内存是 Java 堆外的 、直接向系统申请的内存区间,不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
9909+ 直接内存是 Java 堆外 、直接向系统申请的内存区间,不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
99089910
99099911
99109912
0 commit comments