java基础 集合 特性

虚拟机类加载机制(一)

2018-07-18  本文已影响20人  WJoe

概述

Class文件中描述的各种信息最终都需要加载到虚拟机中之后才能运行和使用。在Java中,类型的加载和连接与初始化是在程序运行期间完成的,所以Java可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。例如,编写一个面向接口的应用程序,可以等到运行时再指定其实际的实现类。

类加载的时机

什么情况下需要开始类加载过程的第一个阶段:"加载"。虚拟机规范中并没强行约束,这点可以交给虚拟机的的具体实现自由把握,但是对于初始化阶段虚拟机规范是严格规定了如下几种情况,如果类未初始化会对类进行初始化。

以上情况称为称对一个类进行“主动引用”,除此种情况之外,均不会触发类的初始化,称为“被动引用”
接口的加载过程与类的加载过程稍有不同。接口中不能使用static{}块。当一个接口在初始化时,并不要求其父接口全部都完成了初始化,只有真正在使用到父接口时(例如引用接口中定义的常量)才会初始化。
被动引用的例子

class SuperClass {
    static {
        System.out.println("superclass init");
    }
    public static int value = 123;
}
 
class SubClass extends SuperClass {
    static {
        System.out.println("subclass init");
    }
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(SubClass.value);// 被动应用1, 程序输出 superclass init , 123
        SubClass[] sca = new SubClass[10];// 被动引用2
    }
}
class ConstClass {
    static {
        System.out.println("ConstClass init");
    }
    public static final String HELLOWORLD = "hello world";
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLOWORLD);// 调用类常量 输出 hello world 即没初始化类
    }
}

类加载可以分为加载、连接(Linking)、初始化。连接包括验证、准备、解析。


类从被加载到虚拟机内存开始到卸载出内存为止,他的整个生命周期包括:

1、加载(Loading)

加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:

二进制流产生的方式:

2、连接

2.1、验证

验证阶段主要是为了确保Class文件的字节流中包含的信息是符合当前虚拟机的。Java语言本身是相对安全的语言,但是Class文件的来源不一定是Java源码编译来的。所以这个时候需要检查输入的字节流。
验证阶段主要是会完成4个阶段的验证:

2.2 准备

准备阶段是正式为类变量在方法区中分配内存并设置变量初始值的阶段。
类变量(static修饰)不是实例变量(在初始化阶段被分配到java堆);初始值为数据类型的零值,而不是程序定义的初始值(字面量)。
特殊情况:final修饰的字段赋值为程序定义的初始值,而不是数据类型零值,虚拟机不会给final修饰的变量赋初始值。

2.3 解析

解析阶段是虚拟机将常量池内的符号引用替换成直接引用的过程。

3 、初始化

初始化是类加载过程的最后一步,到了此阶段,才真正开始执行类中定义的Java程序代码。在准备阶段,类变量已经被赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序指定的主观计划去初始化类变量和其他资源,或者可以从另一个角度来表达:初始化阶段是执行类构造器<clinit>()方法的过程。
该方法由编译器在编译阶段生成,它封装了两部分内容:静态变量的初始化语句和静态语句块。
<clinit>()方法的执行规则:

类加载器明天再写。。。。

上一篇下一篇

猜你喜欢

热点阅读