Skip to content

Commit 47d58be

Browse files
committed
Update Java Notes
1 parent 029168a commit 47d58be

5 files changed

Lines changed: 399 additions & 368 deletions

File tree

DB.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4335,7 +4335,7 @@ EXPLAIN SELECT * FROM table_1 WHERE id = 1;
43354335
| filtered | 按表条件过滤的行百分比 |
43364336
| extra | 执行情况的说明和描述 |
43374337

4338-
MySQL执行计划的局限
4338+
MySQL 执行计划的局限
43394339

43404340
* 只是计划,不是执行 SQL 语句
43414341

@@ -4433,13 +4433,13 @@ SQL 执行的顺序的标识,SQL 从大到小的执行
44334433
| ALL | Full Table Scan,MySQL将遍历全表以找到匹配的行,全表扫描 |
44344434
| index | Full Index Scan,index 与 ALL 区别为 index 类型只遍历索引树 |
44354435
| range | 索引范围扫描,常见于between、<、>等的查询 |
4436-
| ref | 非唯一性索引扫描,返回匹配某个单独值的所有,本质上也是一种索引访问,常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找 |
4436+
| ref | 非唯一性索引扫描,返回匹配某个单独值的所有,本质上也是一种索引访问 |
44374437
| eq_ref | 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描 |
44384438
| const | 当 MySQL 对查询某部分进行优化,并转换为一个常量时,使用该类型访问,如将主键置于where列表中,MySQL就能将该查询转换为一个常量 |
44394439
| system | system 是 const 类型的特例,当查询的表只有一行的情况下,使用system |
44404440
| NULL | MySQL在优化过程中分解语句,执行时甚至不用访问表或索引 |
44414441

4442-
从上到下,性能从差到好,一般来说需要保证查询至少达到 range 级别, 最好达到ref
4442+
从上到下,性能从差到好,一般来说需要保证查询至少达到 range 级别, 最好达到 ref
44434443

44444444

44454445

@@ -4508,7 +4508,7 @@ SHOW PROFILES 能够在做 SQL 优化时分析当前会话中语句执行的资
45084508
![](https://gitee.com/seazean/images/raw/master/DB/MySQL- profiling.png)
45094509

45104510
```mysql
4511-
SET profiling=1; //开启profiling 开关;
4511+
SET profiling=1; #开启profiling 开关;
45124512
```
45134513

45144514
* 执行 SHOW PROFILES 指令, 来查看 SQL 语句执行的耗时:
@@ -5186,7 +5186,7 @@ SQL 提示,是优化数据库的一个重要手段,就是在SQL语句中加
51865186
INSERT INTO tb_test VALUES(1,'Tom'),(2,'Cat'),(3,'Jerry'); -- 连接一次
51875187
```
51885188

5189-
增加 cache 层:在应用中增加缓存层来达到减轻数据库负担的目的。可以部分数据从数据库中抽取出来放到应用端以文本方式存储, 或者使用框架(Mybatis)提供的一级缓存 / 二级缓存,或者使用Redis数据库来缓存数据
5189+
增加 cache 层:在应用中增加缓存层来达到减轻数据库负担的目的。可以部分数据从数据库中抽取出来放到应用端以文本方式存储, 或者使用框架(Mybatis)提供的一级缓存 / 二级缓存,或者使用 Redis 数据库来缓存数据
51905190

51915191

51925192

Issue.md

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,42 +60,35 @@
6060

6161
* **为什么要进行三次握手?**
6262

63-
**原因一**:tcp是全双工可靠的传输协议,全双工意味着双方能够同时向对方发送数据,可靠意味着我发送的数据必须确认对方完整收到了。tcp是通过序列号来保证这两种性质的,**三次握手就是互换序列号**的一次过程
64-
65-
1. A 发送同步信号**SYN** + **A's Initial sequence number**
66-
2. B 确认收到A的同步信号,并记录 A's ISN 到本地,命名 **B's ACK sequence number**
67-
3. B发送同步信号**SYN** + **B's Initial sequence number**
68-
4. A确认收到B的同步信号,并记录 B's ISN 到本地,命名 **A's ACK sequence number**
69-
70-
* 很显然2和3 这两个步骤可以合并,**只需要三次握手,**可以提高连接的速度与效率。
63+
**原因一**:TCP 是全双工可靠的传输协议,全双工意味着双方能够同时向对方发送数据,可靠意味着我发送的数据必须确认对方完整收到。TCP 通过序列号来保证这两种性质的,**三次握手就是互换序列号**的一次过程,可以确保双方的发信和收信能力都是正常的
7164

7265
**原因二**:第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接
7366

7467

7568

7669
* **三次握手的第三次握手发送ACK能携带数据吗?**
7770

78-
答:可以。第三次握手,在客户端发送完ACK报文后,就进入ESTABLISHED状态,当服务器收到这个,服务器变为ESTABLISHED状态,可以直接处理携带的数据。
71+
答:可以。第三次握手,在客户端发送完ACK报文后,就进入 ESTABLISHED 状态,当服务器收到这个,服务器变为ESTABLISHED状态,可以直接处理携带的数据。
7972

80-
* **不携带数据的ACK不会超时重传**
73+
* **不携带数据的 ACK 不会超时重传**
8174

8275

8376

84-
* **为什么TCP4次挥手时等待为2MSL**
77+
* **为什么 TCP4 次挥手时等待为 2MSL**
8578

86-
**原因一:**A发送完释放连接的应答并不知道B是否接到自己的ACK,所以有两种情况
87-
1)如果B没有收到自己的ACK,会超时重传FIN,那么A再次接到重传的FIN,会再次发送ACK
88-
2)如果B收到自己的ACK,也不会再发任何消息,包括ACK
89-
无论是1还是2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL),
90-
这就是**2MSL( Maximum Segment Life)**等待2MSL时间,A就可以放心地释放TCP占用的资源、端口号,此时可以使用该端口号连接任何服务器。
79+
**原因一:**A 发送完释放连接的应答并不知道 B 是否接到自己的 ACK,所以有两种情况
80+
1)如果 B 没有收到自己的 ACK,会超时重传 FIN,那么 A 再次接到重传的 FIN,会再次发送 ACK
81+
2)如果 B 收到自己的 ACK,也不会再发任何消息,包括 ACK
82+
无论是 1 还是 2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:去向ACK消息最大存活时间(MSL) + 来向 FIN 消息的最大存活时间(MSL),
83+
这就是**2MSL( Maximum Segment Life)**等待 2MSL 时间,A 就可以放心地释放 TCP 占用的资源、端口号,此时可以使用该端口号连接任何服务器。
9184

92-
**原因二:**等待一段时间是为了让本次连接持续时间内所产生的报文都从网络中消失,否则存活在网络里的老的TCP报文可能与新TCP连接报文产生冲突(比如连接同一个端口),为避免此种情况,需要耐心等待网络老的TCP连接的活跃报文全部消失,2MSL时间可以满足这个需求(尽管非常保守)
85+
**原因二:**等待一段时间是为了让本次连接持续时间内所产生的报文都从网络中消失,否则存活在网络里的老的TCP报文可能与新TCP连接报文产生冲突(比如连接同一个端口),为避免此种情况,需要耐心等待网络老的 TCP 连接的活跃报文全部消失,2MSL 时间可以满足这个需求(尽管非常保守)
9386

9487

9588

9689
* **为什么连接的时候是三次握手,关闭的时候却是四次握手?**
9790

98-
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手
91+
答:因为当 Server 端收到 Client 端的 SYN 连接请求报文后,可以直接发送 SYN+ACK 报文。其中 ACK 报文是用来应答的,SYN 报文是用来同步的。但是关闭连接时,当 Server 端收到 FIN 报文时,很可能数据还没有处理完成,所以只能先回复一个 ACK 报文,告诉 Client 端,"你发的 FIN 报文我收到了"。只有等到 Server 端所有的报文都发送完了,才能发送 FIN 报文,因此不能一起发送。故需要四步握手
9992

10093

10194

@@ -109,6 +102,21 @@
109102

110103

111104

105+
### 应用层
106+
107+
* 从浏览器地址栏输入 URL 到请求返回发生了什么?
108+
* 进行 URL 解析,进行编码
109+
* DNS 解析,顺序是先查 hosts 文件是否有记录,有的话就会把相对应映射的 IP 返回,然后去本地 DNS 缓存中寻找,然后去找计算机上配置的 DNS 服务器上有或者有缓存,最后去找全球的根 DNS 服务器,直到查到为止
110+
* 查找到 IP 之后,进行 TCP 协议的三次握手,发出 HTTP 请求
111+
* 服务器处理请求,返回响应
112+
* 浏览器解析渲染页面
113+
114+
115+
116+
***
117+
118+
119+
112120

113121

114122
## System

Java.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -592,9 +592,9 @@ public class Test1 {
592592

593593
运算符:
594594

595-
* `>>`运算符:将二进制位进行右移操作,相当于除 2
596-
* `<<`运算符:将二进制位进行左移操作,相当于乘 2
597-
* `>>>`运算符:无符号右移,忽略符号位,空位都以0补齐
595+
* `>>` 运算符:将二进制位进行右移操作,相当于除 2
596+
* `<<` 运算符:将二进制位进行左移操作,相当于乘 2
597+
* `>>>` 运算符:无符号右移,忽略符号位,空位都以0补齐
598598

599599
运算规则:
600600

@@ -4713,7 +4713,7 @@ HashMap继承关系如下图所示:
47134713
static final int TREEIFY_THRESHOLD = 8;
47144714
```
47154715

4716-
为什么 Map 桶中节点个数大于8才转为红黑树
4716+
为什么 Map 桶中节点个数大于 8 才转为红黑树
47174717

47184718
* 在 HashMap 中有一段注释说明:**空间和时间的权衡**
47194719

@@ -4936,22 +4936,22 @@ HashMap继承关系如下图所示:
49364936

49374937
存储数据步骤(存储过程):
49384938

4939-
1. 先通过hash值计算出key映射到哪个桶
4939+
1. 先通过 hash 值计算出 key 映射到哪个桶
49404940

49414941
2. 如果桶上没有碰撞冲突,则直接插入
49424942

49434943
3. 如果出现碰撞冲突:如果该桶使用红黑树处理冲突,则调用红黑树的方法插入数据;否则采用传统的链式方法插入,如果链的长度达到临界值,则把链转变为红黑树
49444944

4945-
4. 如果数组位置相同,通过equals比较内容是否相同:相同则新的value覆盖之前的value,不相同则将新的键值对添加到哈希表中
4946-
5. 如果size大于阈值threshold,则进行扩容
4945+
4. 如果数组位置相同,通过 equals 比较内容是否相同:相同则新的 value 覆盖旧 value,不相同则将新的键值对添加到哈希表中
4946+
5. 如果 size 大于阈值 threshold,则进行扩容
49474947

49484948
```java
49494949
public V put(K key, V value) {
49504950
return putVal(hash(key), key, value, false, true);
49514951
}
49524952
```
49534953

4954-
putVal()方法中key在这里执行了一下hash(),在putVal函数中使用到了上述hash函数计算的哈希值
4954+
putVal() 方法中 key 在这里执行了一下 hash(),在 putVal 函数中使用到了上述 hash 函数计算的哈希值
49554955

49564956
```java
49574957
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
@@ -11300,7 +11300,7 @@ public Object pop() {
1130011300
unused(25+1) + hash(31) + age(4) + lock(3) = 64bit #64位系统
1130111301
```
1130211302

11303-
* **Klass Word**:类型指针,指向该对象的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;在64位系统中,开启指针压缩(-XX:+UseCompressedOops)或者 JVM 堆的最大值小于 32G,这个指针也是 4byte,否则是 8byte(就是 Java 中的一个引用的大小)
11303+
* **Klass Word**:类型指针,指向该对象的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;在64位系统中,开启指针压缩(-XX:+UseCompressedOops)或者 JVM 堆的最大值小于 32G,这个指针也是 4byte,否则是 8byte(就是 **Java 中的一个引用的大小**
1130411304

1130511305
```ruby
1130611306
|-----------------------------------------------------|
@@ -11310,7 +11310,7 @@ public Object pop() {
1131011310
|---------------------------|-------------------------|
1131111311
```
1131211312

11313-
* 数组对象:如果对象是一个数组,那在对象头中还有一块数据用于记录数组长度
11313+
* 数组对象:如果对象是一个数组,那在对象头中还有一块数据用于记录数组长度(12 字节)
1131411314

1131511315
```ruby
1131611316
|-------------------------------------------------------------------------------|
@@ -11352,7 +11352,7 @@ public Object pop() {
1135211352

1135311353
#### 实际大小
1135411354

11355-
浅堆(Shallow Heap):**对象本身占用的内存,不包括内部引用对象的大小**,32 位系统中一个**对象引用占 4 个字节**,每个对象头占用 8 个字节,根据堆快照格式不同,对象的大小会同 8 字节进行对齐
11355+
浅堆(Shallow Heap):**对象本身占用的内存,不包括内部引用对象的大小**,32 位系统中一个对象引用占 4 个字节,每个对象头占用 8 个字节,根据堆快照格式不同,对象的大小会同 8 字节进行对齐
1135611356

1135711357
JDK7 中的 String:2个 int 值共占 8 字节,value 对象引用占用 4 字节,对象头 8 字节,对齐后占 24 字节,为 String 对象的浅堆大小,与 value 实际取值无关,无论字符串长度如何,浅堆大小始终是 24 字节
1135811358

@@ -11396,7 +11396,7 @@ private int hash32;
1139611396

1139711397
#### 节约内存
1139811398

11399-
* 尽量使用基本类型
11399+
* 尽量使用基本数据类型
1140011400

1140111401
* 满足容量前提下,尽量用小字段
1140211402

@@ -11409,7 +11409,7 @@ private int hash32;
1140911409
private int size;
1141011410
```
1141111411

11412-
Mark Word 占 4byte,Klass Word 占 4byte,一个 int 字段占 4byte,elementData 数组占 12(4+4+4),数组中 10 个 Integer 对象占 10×16,所以整个集合空间大小为 184byte(深堆)
11412+
Mark Word 占 4byte,Klass Word 占 4byte,一个 int 字段占 4byte,elementData 数组占 12byte,数组中 10 个 Integer 对象占 10×16,所以整个集合空间大小为 184byte(深堆)
1141311413

1141411414
* 时间用 long/int 表示,不用 Date 或者 String
1141511415

@@ -11421,15 +11421,15 @@ private int hash32;
1142111421

1142211422
#### 对象访问
1142311423

11424-
JVM 是通过栈帧中的对象引用访问到其内部的对象实例
11424+
JVM 是通过**栈帧中的对象引用**访问到其内部的对象实例
1142511425

1142611426
* 句柄访问:Java 堆中会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
1142711427

1142811428
优点:reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集)时只会改变句柄中的实例数据指针,而 reference 本身不需要被修改。
1142911429

1143011430
<img src="https://gitee.com/seazean/images/raw/master/Java/JVM-对象访问-句柄访问.png" style="zoom: 50%;" />
1143111431

11432-
* 直接指针(HotSpot采用):Java 堆对象的布局必须考虑如何放置访问类型数据的相关信息,reference 中直接存储的对象地址
11432+
* 直接指针(HotSpot 采用):Java 堆对象的布局必须考虑如何放置访问类型数据的相关信息,reference 中直接存储的对象地址
1143311433

1143411434
优点:速度更快,**节省了一次指针定位的时间开销**
1143511435

@@ -11475,9 +11475,9 @@ Java 对象创建时机:
1147511475

1147611476
1. 使用 new 关键字创建对象:由执行类实例创建表达式而引起的对象创建
1147711477

11478-
2. 使用 Class 类的 newInstance 方法 (反射机制)
11478+
2. 使用 Class 类的 newInstance 方法反射机制
1147911479

11480-
3. 使用 Constructor 类的 newInstance 方法(反射机制)
11480+
3. 使用 Constructor 类的 newInstance 方法反射机制
1148111481

1148211482
```java
1148311483
public class Student {
@@ -12920,7 +12920,7 @@ double j = i / 0.0;
1292012920
System.out.println(j);//无穷大,NaN: not a number
1292112921
```
1292212922

12923-
分析 i++:从字节码角度分析:a++ 和 ++a 的区别是先执行 iload 还是 先执行 iinc
12923+
**分析 i++**:从字节码角度分析:a++ 和 ++a 的区别是先执行 iload 还是 先执行 iinc
1292412924

1292512925
```java
1292612926
4 iload_1 //存入操作数栈
@@ -13960,15 +13960,15 @@ public class Candy4 {
1396013960
}
1396113961
```
1396213962

13963-
可变参数`String... args`其实是`String[] args` , java 编译器会在编译期间将上述代码变换为:
13963+
可变参数 `String... args` 其实是 `String[] args` , java 编译器会在编译期间将上述代码变换为:
1396413964

1396513965
```java
1396613966
public static void main(String[] args) {
1396713967
foo(new String[]{"hello", "world"});
1396813968
}
1396913969
```
1397013970

13971-
注意:如果调用了foo()则等价代码为`foo(new String[]{})` ,创建了一个空的数组,而不会传递 null 进去
13971+
注意:如果调用了 foo() 则等价代码为 `foo(new String[]{})` ,创建了一个空的数组,而不会传递 null 进去
1397213972

1397313973

1397413974

@@ -17392,7 +17392,7 @@ UML 从目标系统的不同角度出发,定义了用例图、类图、对象
1739217392

1739317393
* 双端检锁机制
1739417394

17395-
在多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作,所以需要使用 `volatile` 关键字
17395+
在多线程的情况下,可能会出现空指针问题,出现问题的原因是 JVM 在实例化对象的时候会进行优化和指令重排序操作,所以需要使用 `volatile` 关键字
1739617396

1739717397
```java
1739817398
public class Singleton {

0 commit comments

Comments
 (0)