写点什么

JVM 类加载器子系统 ClassLoader

作者:java易二三
  • 2023-07-30
    湖南
  • 本文字数:1874 字

    阅读完需:约 6 分钟

1 类加载器与类的加载过程

类加载器子系统的作用:类加载子系统负责从文件或者网络中加载 class 文件,class 文件在文件头有特定的文件标识。

类的加载过程:

加载:

1)通过一个类的全限定名获取定义此类的二进制字节流

2)将这个字节流所表示的静态存储结构转化为方法区的运行时数据结构

3)在内存中生成一个代表这个 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。

链接:

1)验证:目的在于确保 class 文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机的自身安全。

主要包括:文件格式验证,元数据验证,字节码验证,符号引用验证。

2)准备:为类变量分配内存空间,并赋初始默认值。这里不包括 final 修饰的 static,因为 final 修饰的在编译时就会分配了,准备阶段会显式初始化。虚方法表也在此阶段创建并开始初始化,类的变量初始值准备完成后,jvm 会把类的方法表也初始化完毕。

非前向引用:静态代码块可以给定义在静态代码块后的静态变量赋值,但是不能调用。

3)解析:将常量池内的符号引用转坏为直接引用的过程。

初始化:

初始化阶段就是执行类构造器<clinit>()的过程,此方法不需要定义,是 javac 编辑器自动手机所有类变量的赋值动作和静态代码块中的语句合并而来。<clinit>()不同于类的构造器,如果具有父类,jvm 会保证子类的<clinit>()执行前,父类的<clinit>()已经执行完毕。

2 类加载器分类

jvm 支持两周类加载器,分别为引导类加载器(Bootstrap ClassLader,和自定义加载器(User-Definedd ClassLoader).自定义加载器不仅是指开发人员自己定义的类加载器,而是将所有派生类生于抽象类 ClassLoader 的类加载器都划分为自定义类加载器。

常用的三个类加载器:

1)启动类加载器(引导类加载器,Bootstrap ClassLoader)

这个类加载器使用 C/C++语言实现,嵌套在 jvm 内部,用于记载 java 核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar 或 sun.boot.class.path 路径下的内容),用于提供 jvm 自身需要的类。

并不继承 java.lang.ClassLoader,没有父加载器。

出于安全考虑,Bootstrap 启动类加载器只加载包名为 java、javax、sun 等开头的类。

2)扩展类加载器(Extension ClassLoader)

由 java 语言编写,派生自 ClassLoader 类,父类加载器为启动类加载器。从 java.ext.dirs 系统属性所指定的目录中加载类库,或从 jdk 安装目录的 jre/lib/ext 子目录(扩展目录)下安装类库。如果用户创建的 jar 在此目录下,也会自动由扩展类加载器加载。

3)应用程序类加载器(AppClassLoader)

java 语言编写,派生于 ClassLoader 类,父类加载器为扩展类加载器,负责加载环境变量 classpath 或系统属性 java.class.path 指定下的类库。此类加载器是程序中默认的加载器,一般来说,java 应用的类都是由它来完成的。

3 ClassLoader 的使用说明

ClassLoader 类是一个抽象类,除了引导类加载器外斗继承自 ClassLoader。

sun.mis.Laucher 是一个虚拟机的入口应用,扩展类加载器和应用程序类加载器都是都是其定义的内部类。

获取 ClassLoaderd 的途径:

如果是 String 等 java 核心类库,由引导类加载器加载,因为是由 c/c++编写,所以获取不到相应的对象,获取为 null。

1)获取当前类的 classloader :clazz.getClassLoader()

2)获取当前线程上下文的 ClassLoader:Thread.currentThread().getContextClassLoader()

3)获取系统的 ClassLoader:CladdLoader.getSystemClassLoader()

4)获取调用者的 ClassLoaderL:DriverManager.getCallerClassLoader()

4 双亲委派机制

工作原理:如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类加载器去执行,直到向上委托至最顶层的启动类加载器。如果父类能够完成类加载任务,就成功返回,如果不能,子加载器才会尝试自己去加载。

优势:避免类的重复加载。保护程序安全,防止 API 被随意篡改。

沙箱安全机制:

自定义 String 类,但是在加载自定义 String 类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载 jdk 自带的文件,报错信息说没有 main 方法就是因为加载的是 rt.jar 中的 string 类。这样可以保证对 java 核心源代码的保护,这就是沙箱安全机制。

其他:

1)在 jvm 中表示两个 class 对象是否为同一个类存在的两个必要条件:类加载的完整类名必须一致,包括包名,加载这个类的列加载器必须相同。

2)jvm 必须知道一个类型是由启动类加载器还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么 jvm 会将这个类加载器的一个引用作为类型信息的一部分保存在方法去中,当解析一个类型到另外一个类型的引用的时候,jvm 需要保证这两个类的类记载器是相同的。

3)类的被动使用不会导致类的初始化

用户头像

java易二三

关注

还未添加个人签名 2021-11-23 加入

还未添加个人简介

评论

发布
暂无评论
JVM类加载器子系统ClassLoader_编程_java易二三_InfoQ写作社区