小结:jvm 类加载过程
类加载过程
是Java虚拟机(JVM)将字节码文件(.class文件)加载到内存中,并转换为运行时数据结构的过程。这个过程可以分为多个步骤,每个步骤都有其特定的任务和目的。根据你提供的信息,以下是类加载过程的三个主要步骤:
1. 加载
在这个阶段,类加载器通过一个类的全限定名来获取定义此类的二进制字节流。这一步骤包括以下几个子步骤:
- 定位字节源:类加载器需要找到包含类定义的字节码文件。这些字节码文件可能存在于本地文件系统、网络资源、数据库或者其他任何形式的存储介质中。
- 读取字节流:一旦找到了字节码文件,类加载器会读取该文件的内容,将其转化为字节流。
- 创建类对象:类加载器使用读取到的字节流来创建一个
java.lang.Class
对象,这个对象代表了正在被加载的类。
2. 链接
链接阶段的主要任务是将字节流所代表的静态存储结构转化为方法区的运行时数据结构。这个阶段又可以细分为以下三个子阶段:
- 验证:确保字节流中的信息符合Java虚拟机规范的要求,不会对虚拟机造成危害。验证包括字节码验证、符号引用验证等多个方面。
- 准备:为类的静态变量分配内存,并设置默认初始值。例如,对于int类型的静态变量,默认值为0;对于引用类型,默认值为null。
- 解析:将类的常量池内的符号引用替换为直接引用。符号引用是以字符串形式存在的,而直接引用可以直接指向目标。
3. 初始化
在初始化阶段,JVM会执行类构造器<clinit>()
方法,这个方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块,中的语句合并产生的。初始化阶段是执行类中定义的Java程序代码(或者说是字节码)的阶段,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由JVM主导和控制。到了初始化阶段,才真正开始执行类中编写的Java程序代码(或者说是字节码)。
类加载类型
1. 类加载器类型
- Bootstrap Class Loader
由JVM内部实现(如C++),负责加载核心类库(如rt.jar
)。它是所有类加载器的根基,但没有对应的Java对象,因此在代码中不可直接访问。 - Extension Class Loader
加载JRE扩展目录(如jre/lib/ext
)中的类,父加载器为Bootstrap(但通常以null
表示)。 - System/Application Class Loader
加载应用程序类路径(-classpath
或-cp
)的类,父加载器是Extension。 - User-Defined Class Loader
用户自定义的类加载器(需继承ClassLoader
类),可灵活指定其父加载器(默认父加载器是System)。
2. 包含关系
- 不是继承关系:类加载器之间的层次通过组合实现(每个加载器持有父加载器的引用),而非类的继承。例如,
ClassLoader
类中有一个parent
字段指向父加载器。 - 委派模型:加载类时,子加载器会先委派父加载器尝试加载,父加载器失败后子加载器才自行加载。这种“双亲委派”机制确保了核心类的安全性。
3. **图示关系
Bootstrap Class Loader↑(隐含引用)
Extension Class Loader↑(parent字段引用)
System Class Loader↑(parent字段引用)
User-Defined Class Loader(可多个,各自独立)
Java类加载器之间的关系通过委派模型协作,形成逻辑上的层次结构,但并非通过类继承实现,而是通过对象间的引用组合(即包含关系)。具体如下:
// System Class Loader 的 parent 是 Extension Class Loader
ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
ClassLoader parent = systemLoader.getParent(); // 父加载器是 Extension
4. Optional的说明
- Optional可能指Java 9+模块化系统中的类加载器(如
PlatformClassLoader
),或特定场景下的可选加载器(如OSGi、Tomcat的WebApp类加载器)。它们与上述加载器协作,但遵循相同的委派逻辑。
总结
类加载器通过委派链形成包含关系,每个加载器通过parent
字段引用父加载器,而非继承。这种设计保障了核心类库的隔离性与安全性,同时允许用户自定义类加载逻辑。