JVM类加载机制、再续前缘

版权声明:转载标明来源! https://blog.csdn.net/qq_39213969/article/details/88850291

一,准备阶段

1.准备阶段是正是为类变量分配内存并且为类变量初始化值(一般是数据类型的零值)的阶段,这些变量所使用的内存都将在方法区进行分配。
public static int value=123;
注意:这个时候进行分配的变量是类变量(也就是static修饰的变量),而不包括实例变量,实例变量将在对象实例化时随着对象一起分配在java堆中。

2.赋值操作将在代码编译之后,初始化阶段才会执行。(将static类变量赋值的方法是putstatic方法,其存放于类构造器()方法中),所以说静态变量赋值的操作需要在初始化阶段才会执行)。
注意;假设将变量设置为static final属性,编译时javac会将value生成constantvalue属性,在准备阶段虚拟机就会根据constantvalue的设置将value的值赋值为123.

二,解析阶段

3.解析阶段就是将常量池内的符号引用替换为直接引用的过程。
4.符号引用与直接引用的关联:

(1)符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要唯一定位到目标即可。注意:符号引用与java虚拟机实现的内存布局无关,引用的目标也不一定已经加载到内存中。内存布局可以不同但是能接受的符号引用必须是一致的,因为符号引用的字面量形式是明确定义在虚拟机规范的class文件格式中的。
(2)直接引用就是可以直接指向目标的指针,相对偏移量或者能够间接定位到目标的句柄。直接引用是与虚拟机实现的内存布局相关的。注意:同一个符号引用在不同虚拟机上实例翻译出来的直接引用可能不太一样。如果有了直接引用,那么引用的目标就必定在内存中存在了。
(3)符号引用被解析的两个情况:类被加载时就对常量池中的符号引用进行解析;还有就是等到一个符号引用将要被使用前才去解析它;
(4)解析动作主要是针对:类,接口,字段,类,方法,接口方法,方法类型,方法句柄和调用点限定符等引用进行。分别对应常量池的七种常量类型。

5.四种重点的引用解析过程(类或接口,字段,类方法,接口方法)

(1)类或接口(类为D,符号引用为N,接口C)
把代表N的全限定名传递给D的类加载器去加载这个类D(C不是数组类型):加载过程中可能会触发其他类或者接口的加载动作。
先同一加载数组元素类型(接着有虚拟机生成一个代表此数组维度和元素的数组对象);
其那面均无异常,那么实际上C在虚拟机中已经生成了一个类或者接口了。

。。。。。。。。

三,初始化

1.初始化之前,只有在加载阶段用户自定义类加载器参与之外,其余动作均是java虚拟机主导以及控制的。
到了初始化阶段,才真正开始执行类中定义的java程序代码(也就是java字节码)。
注意:在准备阶段,变量已经赋值过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量以及其他资源。(其实初始化阶段就是执行类构造器()方法的过程)
2.()方法是由编译器自动收集类中的所有类变量的赋值动作静态语句块static{}快中的语句合并产生的。
注意:编译器收集的顺序是由
语句在源文件中出现的顺序决定的
,静态语句块中只能访问到定义到静态语句之前的变量,之后可以赋值,但是不可访问。
3.虚拟机会保证在子类的clinit方法执行之前,父类的clinit方法已经执行完毕。clinit方法对于类或者接口来说并不是必需的,如果一个类没有静态语句块,也没有对变量的赋值操作,那么编译器就不为这个类产生clinit方法。
注意:接口中不能有静态语句块但是仍然·有变量初始化的赋值操作。
4.虚拟机保证再多线程环境下,只会有以有一个线程去执行clinit方法(通过加锁,同步的方式保证线程的安全)。

猜你喜欢

转载自blog.csdn.net/qq_39213969/article/details/88850291
今日推荐