Skip to content

Commit 448c4b4

Browse files
committed
Update Java Notes
1 parent 1bd8ecd commit 448c4b4

2 files changed

Lines changed: 1658 additions & 46 deletions

File tree

Java.md

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ public class MethodDemo {
786786
* 如果第 1 个阶段中没有找到适配的方法,那么在允许自动装拆箱,但不允许可变长参数的情况下选取重载方法
787787
* 如果第 2 个阶段中没有找到适配的方法,那么在允许自动装拆箱以及可变长参数的情况下选取重载方法
788788

789-
如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么会选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系,一般会选择形参为参数类型的子类的方法,因为子类时更具体的实现:
789+
如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么会选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系,**一般会选择形参为参数类型的子类的方法,因为子类时更具体的实现**
790790

791791
```java
792792
public class MethodDemo {
@@ -4318,19 +4318,19 @@ TreeSet 集合自排序的方式:
43184318
2. 字符串类型的元素会按照首字符的编号排序
43194319
3. 对于自定义的引用数据类型,TreeSet 默认无法排序,执行的时候报错,因为不知道排序规则
43204320

4321-
自定义的引用数据类型,TreeSet 默认无法排序,需要定制排序的规则,方案有2种
4321+
自定义的引用数据类型,TreeSet 默认无法排序,需要定制排序的规则,方案有 2 种
43224322

43234323
* 直接为**对象的类**实现比较器规则接口 Comparable,重写比较方法:
43244324

4325-
方法:`public int compareTo(Employee o): this是比较者, o是被比较者`
4325+
方法:`public int compareTo(Employee o): this 是比较者, o 是被比较者`
43264326

4327-
* 比较者大于被比较者,返回正数
4327+
* 比较者大于被比较者,返回正数(升序)
43284328
* 比较者小于被比较者,返回负数
43294329
* 比较者等于被比较者,返回 0
43304330

43314331
* 直接为**集合**设置比较器 Comparator 对象,重写比较方法:
43324332

4333-
方法:`public int compare(Employee o1, Employee o2): o1比较者, o2被比较者`
4333+
方法:`public int compare(Employee o1, Employee o2): o1 比较者, o2 被比较者`
43344334

43354335
* 比较者大于被比较者,返回正数
43364336
* 比较者小于被比较者,返回负数
@@ -8443,12 +8443,16 @@ public class AnnotationDemo01 {
84438443

84448444

84458445

8446+
***
8447+
8448+
8449+
84468450
#### 特殊属性
84478451

84488452
注解的特殊属性名称:value
84498453

8450-
* 如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
8451-
* 如果有多个属性,且多个属性没有默认值,那么value是不能省略的
8454+
* 如果只有一个 value 属性的情况下,使用 value 属性的时候可以省略 value 名称不写
8455+
* 如果有多个属性,且多个属性没有默认值,那么 value 是不能省略的
84528456

84538457
```java
84548458
//@Book("/deleteBook.action")
@@ -8470,7 +8474,7 @@ public class AnnotationDemo01{
84708474

84718475
### 元注解
84728476

8473-
元注解是sun公司提供的,用来注解自定义注解
8477+
元注解是 sun 公司提供的,用来注解自定义注解
84748478

84758479
元注解有四个:
84768480

@@ -11107,7 +11111,7 @@ Serial GC、Parallel GC、Concurrent Mark Sweep GC 这三个 GC 不同:
1110711111

1110811112
##### 静态集合
1110911113

11110-
静态集合类的生命周期与JVM程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。原因是长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收
11114+
静态集合类的生命周期与 JVM 程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。原因是**长生命周期的对象持有短生命周期对象的引用**,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收
1111111115

1111211116
```java
1111311117
public class MemoryLeak {
@@ -11184,7 +11188,7 @@ public class UsingRandom {
1118411188

1118511189
##### 改变哈希
1118611190

11187-
当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值不同,这种情况下使用该对象的当前引用作为的参数去 HashSet 集合中检索对象返回 false,导致无法从 HashSet 集合中单独删除当前对象,造成内存泄漏
11191+
当一个对象被存储进 HashSet 集合中以后,就**不能修改这个对象中的那些参与计算哈希值的字段**,否则对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值不同,这种情况下使用该对象的当前引用作为的参数去 HashSet 集合中检索对象返回 false,导致无法从 HashSet 集合中单独删除当前对象,造成内存泄漏
1118811192

1118911193

1119011194

@@ -11280,14 +11284,14 @@ public Object pop() {
1128011284

1128111285
* 普通对象:分为两部分
1128211286

11283-
* Mark Word:用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等
11287+
* **Mark Word**:用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等
1128411288

1128511289
```ruby
1128611290
hash(25) + age(4) + lock(3) = 32bit #32位系统
1128711291
unused(25+1) + hash(31) + age(4) + lock(3) = 64bit #64位系统
1128811292
```
1128911293

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

1129211296
```ruby
1129311297
|-----------------------------------------------------|
@@ -11309,7 +11313,7 @@ public Object pop() {
1130911313

1131011314
实例数据:实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的,都需要记录起来
1131111315

11312-
对齐填充:Padding 起占位符的作用。64 位系统,由于 HotSpot VM 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,就是对象的大小必须是 8 字节的整数倍,而对象头部分正好是 8 字节的倍数(1倍或者2倍),因此当对象实例数据部分没有对齐时,就需要通过对齐填充来补全
11316+
对齐填充:Padding 起占位符的作用。64 位系统,由于 HotSpot VM 的自动内存管理系统要求**对象起始地址必须是 8 字节的整数倍**,就是对象的大小必须是 8 字节的整数倍,而对象头部分正好是 8 字节的倍数(1倍或者2倍),因此当对象实例数据部分没有对齐时,就需要通过对齐填充来补全
1131311317

1131411318
32位系统:
1131511319

@@ -11339,7 +11343,7 @@ public Object pop() {
1133911343

1134011344
#### 实际大小
1134111345

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

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

@@ -11410,14 +11414,14 @@ private int hash32;
1141011414

1141111415
JVM 是通过栈帧中的对象引用访问到其内部的对象实例:
1141211416

11413-
* 句柄访问
11414-
使用该方式,Java 堆中会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
11417+
* 句柄访问:Java 堆中会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
11418+
1141511419
优点:reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集)时只会改变句柄中的实例数据指针,而 reference 本身不需要被修改。
1141611420

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

11419-
* 直接指针(HotSpot采用)
11420-
使用该方式,Java 堆对象的布局必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址
11423+
* 直接指针(HotSpot采用):Java 堆对象的布局必须考虑如何放置访问类型数据的相关信息,reference 中直接存储的对象地址
11424+
1142111425
优点:速度更快,**节省了一次指针定位的时间开销**
1142211426

1142311427
<img src="https://gitee.com/seazean/images/raw/master/Java/JVM-对象访问-直接指针.png" style="zoom: 67%;" />
@@ -11439,7 +11443,7 @@ JVM 是通过栈帧中的对象引用访问到其内部的对象实例:
1143911443
1. 创建阶段 (Created):
1144011444
2. 应用阶段 (In Use):对象至少被一个强引用持有着
1144111445
3. 不可见阶段 (Invisible):程序的执行已经超出了该对象的作用域,不再持有该对象的任何强引用
11442-
4. 不可达阶段 (Unreachable):该对象不再被任何强引用所持有,包括GC Root的强引用
11446+
4. 不可达阶段 (Unreachable):该对象不再被任何强引用所持有,包括 GC Root 的强引用
1144311447
5. 收集阶段 (Collected):垃圾回收器已经对该对象的内存空间重新分配做好准备,该对象如果重写了finalize()方法,则会去执行该方法
1144411448
6. 终结阶段 (Finalized):等待垃圾回收器对该对象空间进行回收,当对象执行完finalize()方法后仍然处于不可达状态时进入该阶段
1144511449
7. 对象空间重分配阶段 (De-allocated):垃圾回收器对该对象的所占用的内存空间进行回收或者再分配
@@ -11458,7 +11462,7 @@ JVM 是通过栈帧中的对象引用访问到其内部的对象实例:
1145811462

1145911463
类在第一次实例化加载一次,后续实例化不再加载,引用第一次加载的类
1146011464

11461-
Java对象创建时机
11465+
Java 对象创建时机
1146211466

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

@@ -11508,17 +11512,17 @@ Java对象创建时机:
1150811512

1150911513
4. 初始化分配的空间:虚拟机将分配到的内存空间都初始化为零值(不包括对象头),保证对象实例字段在不赋值时可以直接使用,程序能访问到这些字段的数据类型所对应的零值
1151011514

11511-
5. 设置对象的对象头:将对象的所属类(类的元数据信息)、对象的HashCode、对象的GC信息、锁信息等数据存储在对象的对象头中
11515+
5. 设置对象的对象头:将对象的所属类(类的元数据信息)、对象的 HashCode、对象的 GC 信息、锁信息等数据存储在对象头中
1151211516

11513-
6. 执行init方法进行实例化:实例变量初始化、实例代码块初始化 、构造函数初始化
11517+
6. 执行 init 方法进行实例化:实例变量初始化、实例代码块初始化 、构造函数初始化
1151411518

1151511519
* 实例变量初始化与实例代码块初始化:
1151611520

11517-
对实例变量直接赋值或者使用实例代码块赋值,编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后 (**Java要求构造函数的第一条语句必须是超类构造函数的调用语句**),构造函数本身的代码之前
11521+
对实例变量直接赋值或者使用实例代码块赋值,编译器会将其中的代码放到类的构造函数中去,并且这些代码会被放在对超类构造函数的调用语句之后 (**Java 要求构造函数的第一条语句必须是超类构造函数的调用语句**),构造函数本身的代码之前
1151811522

1151911523
* 构造函数初始化:
1152011524

11521-
**Java要求在实例化类之前,必须先实例化其超类,以保证所创建实例的完整性**,在准备实例化一个类的对象前,首先准备实例化该类的父类,如果该类的父类还有父类,那么准备实例化该类的父类的父类,依次递归直到递归到Object类。然后从Object类依次对以下各类进行实例化,初始化父类中的变量和执行构造函数
11525+
**Java 要求在实例化类之前,必须先实例化其超类,以保证所创建实例的完整性**,在准备实例化一个类的对象前,首先准备实例化该类的父类,如果该类的父类还有父类,那么准备实例化该类的父类的父类,依次递归直到递归到 Object 类。然后从 Object 类依次对以下各类进行实例化,初始化父类中的变量和执行构造函数
1152211526

1152311527

1152411528

@@ -18697,7 +18701,7 @@ private static final class ProxyClassFactory {
1869718701

1869818702
#### CGLIB
1869918703

18700-
CGLIB 是一个功能强大,高性能的代码生成包,为没有实现接口的类提供代理,为 JDK 动态代理提供了补充
18704+
CGLIB 是一个功能强大,高性能的代码生成包,为没有实现接口的类提供代理,为 JDK 动态代理提供了补充($$Proxy)
1870118705

1870218706
* CGLIB 是第三方提供的包,所以需要引入 jar 包的坐标:
1870318707

0 commit comments

Comments
 (0)