简述类加载机制

一、什么是类加载机制

虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是虚拟机的类加载机制

二、什么情况会导致类的加载

① 遇到 new、getstatic、putstatic 或 invokestatic 这 4 条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化
生成这 4 条指令的常见 Java 代码场景:
new:使用 new 关键字实例化对象
getstatic:读取一个类的静态字段
putstatic:设置一个类的静态字段
invokestatic:调用类的静态方法

② 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化

③ 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

④ 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类

⑤ 当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄时,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化

注意:接口的加载过程与类加载过程稍有不同,接口中不能使用 static{} 语句块,但编译器仍然会为接口生成 () 类构造器,用于初始化接口中所定义的成员变量。接口与类真正有所区别是情况 ③:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口的初始化时,并不要求其父接口全部都完成了初始化,只有在真正用到了父接口的时候才会初始化

三、类加载器

可以通过一个类的全限定名来获取描述此类的二进制字节流,完成这一动作的代码模块被称为类加载器

3.1 类与类加载器

类加载器虽只用于实现类的加载动作,还可以与类一起来确立当前类在 Java 虚拟机中是否是唯一的,两个类被同一个类加载器加载,这两个类才相等

3.2 双亲委派模型

3.2.1 虚拟机划分

a. 从虚拟机角度划分
1.启动类加载器(Bootstrap ClassLoader),由 C++ 语言实现,是虚拟机自身的一部分
2.其它的类加载器,由 Java 语言实现,独立于虚拟机外部,全继承自抽象类 java.lang.ClassLoader

b. 从 Java 开发人员角度划分
1.启动类加载器
2.扩展类加载器
3.应用程序类加载器
4.自定义类加载器(如果有必要,可以自定义)

3.2.2 双亲委派模型

约束:双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当有自己的父类加载器。类加载器之间的父子关系一般不以继承关系实现,而是使用组合关系来复用父加载器的代码

工作过程:类加载器收到一个类加载的请求,自己不会先加载,而是把该请求委派给父类加载器,每一层的类加载器都是如此,因此最终该请求会被传送到顶层的启动类加载器中,只有当父类加载器无法完成加载请求(对应搜索范围内没有找到所需的类)时,子加载器才尝试自己去加载

好处:双亲委派模型可以保证系统中的类在各种类加载器环境中都是同一个类,即使用户自定义一个和系统同名的类,也不能被类加载器加载,保证了 Java 程序的稳定运作,因为无论哪一个类加载器要加载一个类,最终都是委派给最顶端的启动类加载器进行加载

3.2.3 破坏双亲委派模型

双亲委派模型不是强制性的约束模型,Java 中大部分的类加载器都遵循这个模型,但是有例外
1.双亲委派模型是在 JDK 1.2 之后引入的,类加载器是在 JDK 1.0 就已经存在。所以在 JDK 1.2 之前,用户可用继承 java.lang.ClassLoader 去重写 loadClass() 方法
2.当基础类要调用用户的代码时,父类加载器可以请求这类加载器去完成类加载的动作
3.对程序动态性的追求,如:代码热替换、代码热部署等

你可能感兴趣的:(读书笔记,Java基础)