类的生命周期

加载、连接(验证、准备、解析)、初始化、使用、卸载

image.png

加载

步骤:

  1. 获取.class文件的二进制流
  2. 将类元信息写入方法区
  3. 生成对应的Class对象,作为数据访问入口,一般在堆中,hotspot虚拟机放在方法区中

链接

  • 验证

进行数据格式验证,确保.class文件的字节流符合虚拟机的要求

  • 准备

类变量分配内存并设置其初始值

  • 只为类变量分配内存
  • 被final修饰的设置为最终值,没有final修饰的设置为初始值
    • 解析

将常量池中的符号引用替换为直接引用

  • 符号引用:任何字面上的含义
  • 直接引用:直接指向目标的指针、相对偏移量

初始化

执行类构造器()方法的过程
()方法是Javac编译器自动生成物
()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的, 编译器收集的顺序是由语句在源文件中出现的顺序决定的, 静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值, 但是不能访问

类加载器

类的加载:将类的.class文件中的二进制数据读入内存,将其放入方法区中,并创建对应的Class对象,提供数据访问入口

类加载器的分类

  • 引导类加载器BootStrapClassLoader

c++实现

  • 自定义类加载器

Java实现

  • 扩展类加载器Extension Class Loader
  • 系统类加载器System Class Loader
  • 用户自定义类加载器User-Defined ClassLoader

双亲委派模型

什么是双亲委派模型

双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,先把这个请求委派给父类加载器完成,只有当父加载器不能加载该类时,子加载器才会自己去加载。

为什么需要双亲委派模型

避免他人自定义的系统同名类(例如java.lang.String)加载进内存,引入病毒代码

如何实现

关键方法:loadClass()、findClass()

打破双亲委派模型需要重写loadClass()方法
双亲委派模型实现
image.png

findClass():类加载器具体的加载逻辑,自定义类加载器需要重写该方法

自定义类加载器

为什么要自定义类加载器

  • 隔离加载类

模块隔离,把类加载到不同的应用选中。比如tomcat这类web应用服务器,内部自定义了好几中类加载器,用于隔离web应用服务器上的不同应用程序。

  • 修改类加载方式

除了Bootstrap加载器外,其他的加载并非一定要引入。根据实际情况在某个时间点按需进行动态加载。

  • 扩展加载源

比如还可以从数据库、网络、或其他终端上加载

  • 防止源码泄漏

java代码容易被编译和篡改,可以进行编译加密,类加载需要自定义还原加密字节码。

自定义类加载器实现

实现方式:

  1. 继承ClassLoader类
  2. 在自定义ClassLoader,重写findClass方法

ClassLoader源码解析