目录:
上一篇文章总结了字节码相关的知识,本文则将总结类加载相关知识。包括
- 类是在什么时候被加载的。
- 类是如何被加载的。
- 类的双亲加载机制是什么。
1.类在什么时候被加载
- 使用new创建对象,读取类的静态字段或者方法的时候
- 使用反射进行调用的时候
- 初始化一个类,且其父类未加载时,触发其父类加载
- 虚拟机启动时,需要执行一个主类(包含main方法的类)
- 动态语言解析后触发调用静态的类属性或方法
2.类加载过程
类加载的过程是加载-连接-初始化,而连接又包含了验证-准备-解析。
- 加载
- 1.通过全限定名来获取此类的二进制字节码(加载字节码)
- 2.将字节码所代表的静态存储结构转存到方法区的运行时数据结构(加载静态数据)
- 3.在内存中生成一个代表该类的java.kang.Class对象(加载类对象)
- 数组类由虚拟机直接创建
- 验证:验证字节码是否符合要求
- 文件格式验证:如魔数,版本,静态索引是否指向准确等。
- 元数据验证:是否由父类,是否继承了final类,是否实现了抽象父类的所有要求实现的方法等。
- 字节码验证:确定程序语义合法,符合逻辑,保证不会危害虚拟机等
- 符号引用验证:在将符号引用转化为直接引用时,验证引用是否正确。
- 准备:分配类变量内存
- 为类变量分配内存
- 初始化0值
- final修饰的类赋值
- 解析:解析符号引用为直接引用
- 常量池符号引用
- 可能会引起级联类加载
- 方法引用解析:查找类方法,查找接口方法,查找父类方法,查找抽象方法,查找父类
- 初始化:执行静态变量和静态代码块的初始化,按代码顺序执行
- ():合并所有的静态代码快和类变量赋值语句组合成的方法。
3.类加载器
四种类加载器
- 启动类加载器:这类加载器是为了加载运行虚拟机所需要的类,加载路径是:<JAVA_HOME>/lib。
- 扩展类加载器:这类加载器是为了加载拓展类,如zipfs.jar,加载路径是:<JAVA_HOME>/lib/ext。
- 系统类加载器:这类加载器就是加载我们编写的程序的类的了,加载路径是-classpath所指定的路径
- 自定义类加载器:为了隔离不同的系统的类,如tomcat,不同的web可能使用不同的第三方版本,利用不同的类加载器隔离开。具体的实现方式是继承ClassLoader类,如果不想破坏双亲委托委派模式,只需要重写findClass,如果需要破坏双亲委托模式,则需要重写loadClass方法。
双亲委托委派模式
所谓双亲委托委派模式其实就是,在当前的类加载器收到加载类的请求时,会先委派其父类加载(这里的父类不是使用继承方式实现的。而是使用组合),如果父类反馈无法加载时才会去加载该类。这样做的目的是保证安全,该被父类加载器加载的类就应该被父类加载,防止子类加载器篡改基础的类。
不过双亲委托委派模式并不是强制的约束模型,而是一种建议,实际上并不是所有的类加载器都是遵循该模式的,如JDK1.2之前的类加载器。
类的唯一标识
因为同一个类可以被不同的类加载器加载,所有判断类是否相等,实际上还要判断他们是否由同一个类加载器加载。