JAVA从入门到基础(七) 一类加载器
一 Class装载验证流程
- 加载:装载类的第一个阶段会取得类的二进制流,之后转为方法区数据结构并在Java堆中生成对应的java.lang.Class对象。
链接
验证
- 目的:保证Class流的格式是正确的
文件格式的验证
是否以0xCAFEBABE开头
版本号是否合理
- 元数据验证
- 是否有父类?
- 是否继承了final类?
- 非抽象类实现了所有的抽象方法!
- 字节码验证 (很复杂)
- 运行检查
- 栈数据类型和操作码数据参数吻合
- 跳转指令指定到合理的位置
- 符号引用验证
- 常量池中描述类是否存在
- 访问的方法或字段是否存在且有足够的权限
准备
- –分配内存,并为类设置初始值 (方法区中)
- public static int v=1;
- 在准备阶段中,v会被设置为0
- 在初始化的中才会被设置为1
- 对于static final类型,在准备阶段就会被赋上正确的值
- public static final int v=1;
- –分配内存,并为类设置初始值 (方法区中)
- 解析
- 为了能真正使用,需要将符号引用替换为直接引用(指针或者地址偏移量引用对象一定在内存)
- 初始化
- 执行类构造器
- 对static变量 赋值语句
- static{}语句,会被执行。
- 子类的调用前保证父类的被调用
- 是线程安全的
- 执行类构造器
二 什么是类装载器ClassLoader
ClassLoader是一个抽象类。
ClassLoader的实例将读入Java字节码将类装载到JVM中。
ClassLoader可以定制,满足不同的字节码流获取方式,可以从网络中加载,也可以从文件加载。
ClassLoader负责类装载过程中的加载阶段。
public Class <?> loadClass(String name) throws ClassNotFoundException
,载入并返回一个Classprotected final Class<?> defineClass(byte[] b, int off, int len)
,定义一个类,不公开调用。protected Class<?> findClass(String name) throws ClassNotFoundException
,loadClass回调该方法,自定义ClassLoader的推荐做法。protected final Class<?> findLoadedClass(String name)
寻找已经加载的类。 如图所示为ClassLoader结构图,在协同工作过程中,自底向上检查类是否加载,在寻找一个类时,首先在当前的ClassLoader下寻找是否已加载该类,如果自定义Class类无法找到该类,则不会加载,则将请求发送到父类,看父类是否有此类,如果有则返回,如果没有则再将请求发送到父类,直到BootStrap ClassLoader,之后进行自顶向下的对类进行加载。
在加载过程中存在双亲模式的问题:顶层ClassLoader,无法加载底层ClassLoader的类,为了解决此问题,可以使用Thread. setContextClassLoader(),一个上下文加载器,此加载器不完全是一个加载器,可以理解为是一个角色,用以解决顶层ClassLoader无法访问底层ClassLoader的类的问题,此加载器的基本思想是,在顶层ClassLoader中,传入底层ClassLoader的实例。从而突破双亲模式的局限性。
- BootStrap ClassLoader (启动ClassLoader)
- Extension ClassLoader (扩展ClassLoader)
- App ClassLoader (应用ClassLoader/系统ClassLoader)
- Custom ClassLoader(自定义ClassLoader)
- 每个ClassLoader都有一个Parent作为父亲
三 热替换
- 当一个class被替换后,系统无需重启,替换的类立即生效。使用ClassLoader可以实现热替换。