🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 动态加载 Java程序在运行时并不一定被完整加载,只有当发现该类还没有加载时,才去本地或远程查找类的.class文件并验证和加载; 当程序创建了第一个对类的静态成员的引用(如类的静态变量、静态方法、构造方法——构造方法也是静态的)时,才会加载该类。Java的这个特性叫做:动态加载。 ### 一个类的初始化包括3个步骤 * 加载(Loading),由类加载器执行,查找字节码,并创建一个Class对象(只是创建); * 链接(Linking),验证字节码,为静态域分配存储空间(只是分配,并不初始化该存储空间),解析该类创建所需要的对其它类的应用; * 初始化(Initialization),首先执行静态初始化块static{},初始化静态变量,执行静态方法(如构造方法)。 根据java虚拟机规范,所有java虚拟机实现必须在每个类或接口被java程序首次主动使用时才初始化。 ### 主动使用有以下6种: * 创建类的实例 * 访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化) * 调用类的静态方法 * 反射(Class.forName(xxx.xxx.xxx)) * 初始化一个类的子类(相当于对父类的主动使用),不过直接通过子类引用父类元素,不会引起子类的初始化(参见示例6) * Java虚拟机被标明为启动类的类(包含main方法的) ### Bootstrap CLassloder 由C++编写的,它本身是虚拟机的一部分,所以它并不是一个JAVA类,也就是无法在java代码中获取它的引用 JVM启动时通过Bootstrap类加载器加载rt.jar等核心jar包中的class文件,之前的int.class,String.class都是由它加载 Bootstrap没有父加载器,但是它却可以作为任何一个ClassLoader的父加载器。比如ExtClassLoader 这句话的理解,必须结合后文中的 loadClass()过程,也就是在双亲委托模型中向上迭代父加载器查找时,如果父加载器为null,则jvm内置的加载器去替代,也就是Bootstrap ClassLoader ### Extention ClassLoader 加载目录%JRE\_HOME%\\lib\\ext目录下的jar包和class文件。 ### AppClassLoader 加载当前应用的classpath的所有类 java虚拟机的入口应用,sun.misc.Launcher ## 双亲委托 ### loadClass的实现 (向下一直找缓存,向上找实现) 1. 一个AppClassLoader查找资源时,先看看缓存是否有,缓存有从缓存中获取,否则委托给父加载器。 2. 递归,重复第1步的操作。 3. 如果ExtClassLoader也没有加载过,则由Bootstrap ClassLoader出面。 4. Bootstrap ClassLoader首先查找缓存,如果没有找到的话,就去找自己的规定的路径下,也就是sun.mic.boot.class下面的路径。找到就返回,没有找到,让子加载器自己去找 5. Bootstrap ClassLoader如果没有查找成功,则ExtClassLoader自己在java.ext.dirs路径中去查找,查找成功就返回,查找不成功,再向下让子加载器找 6. ExtClassLoader查找不成功,AppClassLoader就自己查找,在java.class.path路径下查找。找到就返回。如果没有找到就让子类找 7. 如果没有子类会抛出各种异常 ### 为什么要使用这种双亲委托模式呢? * 【重复】因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。 * 【安全】考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String.class来动态替代java核心api中定义类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String.class已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoade 自定义一个ClassLoader,默认加载路径为D:\\lib下的jar包和资源 ### NoClassDefFoundError和ClassNotFoundExceptiom NoClassDefFoundError:当java源文件已编译成.class文件,但是ClassLoader在运行期间在其搜寻路径load某个类时,没有找到.class文件则报这个错 ClassNotFoundException:试图通过一个String变量来创建一个Class类时不成功则抛出这个异常