美文网首页
Java基础之类加载机制

Java基础之类加载机制

作者: youzhihua | 来源:发表于2019-11-29 17:57 被阅读0次

    一、类加载过程

    Java的类加载过程总共包含三大步,分别为:装载、链接和初始化;需要注意的是,这三个步骤并不是简单的串行,而有可能交叉并行的,下面详细介绍下这几个步骤。

    1.1 装载

    装载的任务主要有:

    • 找到Java的字节码文件,将其二进制字节流加载到内存中。
    • 将静态的数据结构转化为运行时数据结构并存入方法区。
    • 创始化一个Class对象放入Java堆中,作为方法区数据的访问入口。

    1.2 链接

    链接可以细分为验证、准备和解析三个步骤。

    1.2.1 验证

    验证是确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全,主要包含以下四种验证方式:

    • 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以 0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。

    • 元数据验证:对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了 java.lang.Object之外。

    • 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

    • 符号引用验证:确保解析动作能正确执行。

    虽然验证功能很有必要,但是我们也可以通过设置 -Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

    1.2.2 准备

    准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。

    • 此阶段处理的变量仅包括static修饰的类变量,不包括类的成员变量;类的成员变量是在初始化阶段,在堆区处理的。
    • 若仅仅是static修饰,便只给它赋默认值,比如整型是0,对象是null,而不是我们显示设置的值。
    • 若final和static同时修饰,会直接给它赋显示设置的值。

    例如 public static int value=10:在此阶段被赋值为0,而public final static int value = 10,在此阶段被赋值为10。

    1.2.3 解析

    解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

    • 符号引用就是一组符号来描述目标,可以是任何字面量。

    • 直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

    1.3 初始化

    初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。

    • 初始化时机

    1.反射(Class.forName)
    2.使用new关键字
    3.其子类要进行初始化操作
    4.操作了该类的静态成员:静态变量使用和赋值以及静态方法的使用

    二、类加载器

    2.1 类加载器类型

    类加载器可以大致划分为以下三类:

    • 启动类加载器: BootstrapClassLoader,负责加载存放在 JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被 -Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.开头的类均被 BootstrapClassLoader加载)。启动类加载器是无法被Java程序直接引用的。
    • 扩展类加载器: ExtensionClassLoader,该加载器由 sun.misc.Launcher$ExtClassLoader实现,它负责加载 JDK\jre\lib\ext目录中,或者由 java.ext.dirs系统变量指定的路径中的所有类库(如javax.开头的类),开发者可以直接使用扩展类加载器。
    • 应用程序类加载器: ApplicationClassLoader,该类加载器由 sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

    2.2双亲委派机制

    • 当 AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。

    • 当 ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。

    • 如果 BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class),会使用 ExtClassLoader来尝试加载;

    • 若ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException。

    使用双亲委派机制的原因:

    • 防止系统加载多份相同的class文件
    • 保证程序的安全性,使系统的class文件不会被官方之外的类加载器加载

    相关文章

      网友评论

          本文标题:Java基础之类加载机制

          本文链接:https://www.haomeiwen.com/subject/rurgwctx.html