-
类的加载过程:加载-验证-准备-解析-初始化
-
加载阶段(加载阶段主要做三件事情):
(1). 通过类的全限名来获取此类的二进制流。
(2). 将这个字节流所代表的的静态存储结构转化为方法区中可运行的数据结构。
(3). 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区中这个类的各种数据结构的访问入口。
-
验证
为了确保Class文件中的字节流中包含的信息符合当前虚拟机的要求。
-
准备
(1). 为类变量分配内存并设置类变量的初始值(这些变量所需要的内存将在方法去中进行分配),初始值是指0或者null,所以我们在声明一个类变量时不需要去附0值或附为null。
(2). 注意不包括实例变量,实例变量将会在对象实例化时随着对象一起被分配在堆中。
(3). 如果说被final修饰,则会直接赋值。
-
解析
将符号引用装换为直接引用的过程。
(1). 符号引用:符号引用以一组符号来描述所应用的目标,符号可以是任意形式的字面量,只要使用时能够无歧义的定位目标即可。
(2). 直接引用:可以是直接指向目标的指针,或者句柄。 -
初始化
(1) 在此阶段才开始真正的执行java代码
(2) 编译器会自动收集类中的类变量赋值语句与静态代码块语句合并生成一个方法(类构造器方法)。
(3) 虚拟机会保证在自类的方法执行前,父类的方法已经执行完毕。
(4) 虚拟机会保证一个类的()方法在所线程环境中被正确地加锁,同步。如果多个线程同时去初始化一个类,那么只要一个线程去执行类的()方法,其它线程都需要阻塞等待。
-
加载,验证,准备,初始化的顺序是确定的,而解析阶段是不一定的,解析阶段有可能发生在初始化之后与java中的运行时多态有关。
-
有一下几种情况需要对类进行初始化:
(1) 使用new实例化对象时,读取或设置一个类的静态字段时,调用一个类的静态方法时。
(2) 使用java.lang.reflect包的方法对类进行反射调用时。
(3) 当初始化一个类,其父类还没有被初始化时。
(4) 虚拟机启动时包含main()方法的那个类。