@@ -442,7 +442,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
442
442
443
443
# 四、类加载机制
444
444
445
- 类是在运行期间第一次使用时动态加载的,而不是编译时期一次性加载。因为如果在编译时期一次性加载 ,那么会占用很多的内存。
445
+ 类是在运行期间第一次使用时动态加载的,而不是一次性加载。因为如果一次性加载 ,那么会占用很多的内存。
446
446
447
447
## 类的生命周期
448
448
@@ -511,13 +511,9 @@ public static final int value = 123;
511
511
512
512
### 5. 初始化
513
513
514
- 初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 < ; clinit>() 方法的过程。
514
+ 初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 < ; clinit>() 方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
515
515
516
- 在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
517
-
518
- < ; clinit>() 方法具有以下特点:
519
-
520
- - 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
516
+ < ; clinit>() 是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序决定。特别注意的是,静态语句块只能访问到定义在它之前的类变量,定义在它之后的类变量只能赋值,不能访问。例如以下代码:
521
517
522
518
``` java
523
519
public class Test {
@@ -529,9 +525,7 @@ public class Test {
529
525
}
530
526
```
531
527
532
- - 与类的构造函数(或者说实例构造器 < ; init>())不同,不需要显式的调用父类的构造器。虚拟机会自动保证在子类的 < ; clinit>() 方法运行之前,父类的 < ; clinit>() 方法已经执行结束。因此虚拟机中第一个执行 < ; clinit>() 方法的类肯定为 java.lang.Object。
533
-
534
- - 由于父类的 < ; clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码:
528
+ 由于父类的 < ; clinit>() 方法先执行,也就意味着父类中定义的静态语句块的执行要优先于子类。例如以下代码:
535
529
536
530
``` java
537
531
static class Parent {
@@ -550,11 +544,9 @@ public static void main(String[] args) {
550
544
}
551
545
```
552
546
553
- - < ; clinit>() 方法对于类或接口不是必须的,如果一个类中不包含静态语句块,也没有对类变量的赋值操作,编译器可以不为该类生成 < ; clinit>() 方法。
554
-
555
- - 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 < ; clinit>() 方法。但接口与类不同的是,执行接口的 < ; clinit>() 方法不需要先执行父接口的 < ; clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 < ; clinit>() 方法。
547
+ 接口中不可以使用静态语句块,但仍然有类变量初始化的赋值操作,因此接口与类一样都会生成 < ; clinit>() 方法。但接口与类不同的是,执行接口的 < ; clinit>() 方法不需要先执行父接口的 < ; clinit>() 方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的 < ; clinit>() 方法。
556
548
557
- - 虚拟机会保证一个类的 < ; clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 < ; clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 < ; clinit>() 方法完毕。如果在一个类的 < ; clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。
549
+ 虚拟机会保证一个类的 < ; clinit>() 方法在多线程环境下被正确的加锁和同步,如果多个线程同时初始化一个类,只会有一个线程执行这个类的 < ; clinit>() 方法,其它线程都会阻塞等待,直到活动线程执行 < ; clinit>() 方法完毕。如果在一个类的 < ; clinit>() 方法中有耗时的操作,就可能造成多个线程阻塞,在实际过程中此种阻塞很隐蔽。
558
550
559
551
## 类初始化时机
560
552
0 commit comments