auto commit
This commit is contained in:
parent
d302e82773
commit
094757bc98
31
notes/JVM.md
31
notes/JVM.md
|
@ -510,10 +510,21 @@ System.out.println(ConstClass.HELLOWORLD);
|
||||||
|
|
||||||
主要有以下 4 个阶段:
|
主要有以下 4 个阶段:
|
||||||
|
|
||||||
1. 文件格式验证
|
**1. 文件格式验证**
|
||||||
2. 元数据验证(对字节码描述的信息进行语义分析)
|
|
||||||
3. 字节码验证(通过数据流和控制流分析,确保程序语义是合法、符合逻辑的,将对类的方法体进行校验分析)
|
验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理。
|
||||||
4. 符号引用验证
|
|
||||||
|
**2. 元数据验证**
|
||||||
|
|
||||||
|
对字节码描述的信息进行语义分析,以保证其描述的信息符合 Java 语言规范的要求。
|
||||||
|
|
||||||
|
**3. 字节码验证**
|
||||||
|
|
||||||
|
通过数据流和控制流分析,确保程序语义是合法、符合逻辑的。
|
||||||
|
|
||||||
|
**4. 符号引用验证**
|
||||||
|
|
||||||
|
发生在虚拟机将符号引用转换为直接引用的时候,对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验。
|
||||||
|
|
||||||
### 3.3 准备
|
### 3.3 准备
|
||||||
|
|
||||||
|
@ -539,7 +550,7 @@ public static final int value = 123;
|
||||||
|
|
||||||
### 3.5 初始化
|
### 3.5 初始化
|
||||||
|
|
||||||
初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。
|
初始化阶段才真正开始执行类中的定义的 Java 程序代码。初始化阶段即虚拟机执行类构造器 <clinit>() 方法的过程。
|
||||||
|
|
||||||
在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。
|
||||||
|
|
||||||
|
@ -574,7 +585,7 @@ static class Sub extends Parent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println(Sub.B); // 输出结果是父类中的静态变量值 A,也就是 2
|
System.out.println(Sub.B); // 输出结果是父类中的静态变量 A 的值 ,也就是 2。
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -590,7 +601,7 @@ public static void main(String[] args) {
|
||||||
|
|
||||||
### 4.1 类与类加载器
|
### 4.1 类与类加载器
|
||||||
|
|
||||||
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在 Java 虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。通俗而言:比较两个类是否“相等”(这里所指的“相等”,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果,也包括使用 instanceof() 关键字对做对象所属关系判定等情况),只有在这两个类时由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
|
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在 Java 虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。通俗而言:比较两个类是否“相等”(这里所指的“相等”,包括类的 Class 对象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回结果,也包括使用 instanceof() 关键字做对象所属关系判定等情况),只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
|
||||||
|
|
||||||
### 4.2 类加载器分类
|
### 4.2 类加载器分类
|
||||||
|
|
||||||
|
@ -600,7 +611,7 @@ public static void main(String[] args) {
|
||||||
|
|
||||||
从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
|
从 Java 开发人员的角度看,类加载器可以划分得更细致一些:
|
||||||
|
|
||||||
- 启动类加载器(Bootstrap ClassLoader) 此类加载器负责将存放在 <JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器,直接使用 null 代替即可。
|
- 启动类加载器(Bootstrap ClassLoader) 此类加载器负责将存放在 <JAVA_HOME>\lib 目录中的,或者被 -Xbootclasspath 参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar,名字不符合的类库即使放在 lib 目录中也不会被加载)类库加载到虚拟机内存中。 启动类加载器无法被 Java 程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给启动类加载器,直接使用 null 代替即可。
|
||||||
|
|
||||||
- 扩展类加载器(Extension ClassLoader) 这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 <Java_Home>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。
|
- 扩展类加载器(Extension ClassLoader) 这个类加载器是由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将 <Java_Home>/lib/ext 或者被 java.ext.dir 系统变量所指定路径中的所有类库加载到内存中,开发者可以直接使用扩展类加载器。
|
||||||
|
|
||||||
|
@ -614,11 +625,11 @@ public static void main(String[] args) {
|
||||||
|
|
||||||
**工作过程**
|
**工作过程**
|
||||||
|
|
||||||
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器,每一个层次的加载器都是如此,依次递归,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成此加载请求(它搜索范围中没有找到所需类)时,子加载器才会尝试自己加载。
|
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载,而是把这个请求委派给父类加载器,每一个层次的加载器都是如此,依次递归。因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成此加载请求(它搜索范围中没有找到所需类)时,子加载器才会尝试自己加载。
|
||||||
|
|
||||||
**好处**
|
**好处**
|
||||||
|
|
||||||
使用双亲委派模型来组织类加载器之间的关系,使得 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类 java.lang.Object,它存放再 rt.jar 中,无论哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型,由各个类加载器自行加载的话,如果用户编写了一个称为`java.lang.Object 的类,并放在程序的 ClassPath 中,那系统中将会出现多个不同的 Object 类,程序将变得一片混乱。如果开发者尝试编写一个与 rt.jar 类库中已有类重名的 Java 类,将会发现可以正常编译,但是永远无法被加载运行。
|
使用双亲委派模型来组织类加载器之间的关系,使得 Java 类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类 java.lang.Object,它存放在 rt.jar 中,无论哪个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此 Object 类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型,由各个类加载器自行加载的话,如果用户编写了一个称为java.lang.Object 的类,并放在程序的 ClassPath 中,那系统中将会出现多个不同的 Object 类,程序将变得一片混乱。如果开发者尝试编写一个与 rt.jar 类库中已有类重名的 Java 类,将会发现可以正常编译,但是永远无法被加载运行。
|
||||||
|
|
||||||
**实现**
|
**实现**
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user