1- 类的加载、连接和初始化

这一部分会介绍java.lang.reflect包下的接口和类,包括Class、Method、Field、Constructor和Array,这些类分别代表类、方法、变量、构造器和数组。Java程序可以使用这些类动态的获取某个对象、某个类的运行时信息,可以动态,的创建Java对象,动态调用Java方法,访问并修改对象的成员变量值。还有该包下的两个接口,Type是Class类实现的接口,ParameterizedType则代表带泛型参数的类型。

也介绍使用Proxy和InvocationHandler来创建JDK动态代理。和JDK动态代理和AOP的内在关系。

JVM和类

当运行某个java程序时,会启动一个java虚拟机进程,不管该Java程序有多么复杂,有多少线程,他们都处于Java虚拟机进程中,同一个JVM的所有线程、所有变量都使用JVM进程的内存区。

当系统出现以下几种情况,JVM进程被终止:

  • 程序运行到正常结束
  • 程序运行到System.exit()或Runtime.getRuntime().exit()代码
  • 程序执行过程中遇到未捕获的异常或错误而结束
  • 程序所在平台强制结束了JVM进程

类的加载

当程序使用某个类时,如果该类还未被加载到内存中,系统会通过加载、连接、初始化三个步骤来对该类进行初始化,没有意外的话,JVM会连续完成这三个步骤,所以也统称为类加载或类初始化。

类加载是指将该类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之建立一个java.lang.Class文件。

类的加载由类加载器完成,类加载器通常由JVM提供。JVM提供的类加载器通常称为系统类加载器,除此,开发者可以继承ClassLoader基类来创建自己的类加载器。

通过使用不用的类加载器,可以从不同来源加载类的二进制数据,通常由以下几种来源:

  • 从本地文件中加载class文件,这是最常用的
  • 从JAR包加载class文件,这种也很常见,导入的jar包就是使用这种方式,例如JDBC编程用到的驱动类jar包
  • 通过网络加载class文件
  • 把一个Java源文件动态编译、并执行加载

类加载器无需等到 首次使用该类 才加载,Java虚拟机允许系统预先加载某些类。

类的连接

当类被加载后,系统为之生成一个对应的Class对象,然后进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中,连接又可分为三个阶段:

  • 验证:用于检验被加载的类是否有正确的内部结构,并和其他类协调一致
  • 准备:负责为类的类变量分配内存,并设置默认初始值
  • 解析:将类的二进制数据中的符号引用转换为直接饮用

类的初始化

虚拟机对类负责初始化,主要就是对类变量进行初始化,Java类变量指定初始值有两种方式:

  1. 声明类变量时指定初始值
  2. 使用静态初始化块指定初始值

JVM初始化一个类包括几个步骤:

  • 假如这个类还没有被加载和连接,程序先加载并连接该类
  • 假如该类的直接父类还没有被初始化,则先初始化该直接父类
  • 假如类中有初始化语句,系统则依次执行这些初始化语句

注意:当执行第二个步骤时,系统对直接父类的初始化也遵循这三个步骤,如果该直接父类的父类也没有被初始化,那么系统会先初始化父类的直接父类,以此类推。所以JVM最先初始化的总是Object类。

类初始化的时机

当Java程序首次通过下面6种方式来使用某个类或接口时,系统会初始化该类或接口。

  • 创建类的实例。包括,使用new操作符来创建实例,通过反射来创建实例,通过反序列化创建实例
  • 调用某个类的类方法
  • 访问某个类的类变量,或为该类变量赋值
  • 使用反射强制创建某个类或接口对应的Class对象,例如Class.forName("Person"),如果系统未初始化Person类,那么这行代码会导致Person类被初始化,并返回对应的Class对象。
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

**注意:**除此之外。对于final型的类变量,如果该类变量的值在编译时就可确定下来,那么这个类变量相当于宏变量,java编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类初始化。

​ 如果final类变量在编译时不能确定下来,必须等到运行时才可确定,如果通过该类访问类变量,会导致该类被初始化。

当使用ClassLoader加载该类时,并不会导致该类的初始化,它加载该类。当使用Class.forName()静态方法才会初始化该类。


1- 类的加载、连接和初始化
https://zhaoquaner.github.io/2022/05/11/Java/类加载机制和反射/1- 类的加载、连接和初始化/
更新于
2022年5月22日
许可协议