Java基础之类加载机制

一、类加载过程

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文件不会被官方之外的类加载器加载
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务