Skip to content

Commit 9c566cb

Browse files
committed
Update Java Notes
1 parent 47d58be commit 9c566cb

File tree

3 files changed

+457
-887
lines changed

3 files changed

+457
-887
lines changed

Java.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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

46044606
JDK7 对比 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

46914693
3. 默认的负载因子,默认值是 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

49044906
1. 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

Comments
 (0)