1.1 简介
jvm执行的字节码是由类加载器加载,class文件经过加载、验证、准备、解析、初始化,被转化为实例对象,供jvm使用。
java的类加载器为动态加载,jvm启动时,将保证程序运行的基础类一次加载,其他的类只在用到时才被加载进内存。
1.2 标准类加载器
系统提供了三种标准类加载器:
1.2.1 BootstrapClassLoader
最顶层的类加载器,有c++编写,集成在jvm内部,主要加载核心类库
1.2.2 ExtentionClassLoader
扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件
1.2.3 AppclassLoader也称为SystemAppClass
加载当前应用的classpath的所有类。
加载器有优先级。一般自定义的加载器CustomClassLoader继承自AppClassLoader,
那么CustomClassLoader的父加载器就是AppClassLoader,
AppClassLoader的父加载器是ExtentionClassLoader,
ExtentionClassLoader的父加载器为BootstrapClassLoader
1.3 双亲委派
加载类时,当前加载器已经加载,则直接使用
如果本加载器没加载过,则询问父类有么有加载。如果父类已加载,使用父类的加载器。
如果最顶层的加载器没有加载过,则查找class文件。
如果最顶层的加载器找到文件,直接加载并使用
如果最顶层的加载器未找到文件,则让子加载器去查找并加载。
如果子加载器找到,则加载并使用
如果最底层的加载器也未找到,则抛ClassNotFoundException
总的原则就是,查找类是否加载过从最底层开始,没加载过从最高层的加载器开始查找并加载
1.4 双亲委派的好处
使一个类只加载一次
保护核心类不被替代或覆盖(如自定义String类型覆盖系统String)
1.5 主要方法
//首先会通过父类加载器进行加载,如果所有父类加载器都无法加载,再通过用户自定义的findClass方法进行加载。如果父类加载器可以加载这个类或者当前类已经存在于某个父类的容器中了,这个类是不会再次被加载的,此时用户自定义的findClass方法就不会被执行了。
Class<?> findClass(String name)
//此时首先是通过用户自定义的类加载器来判断该类是否可加载,如果可以加载就由自定义的类加载器进行加载,如果不能够加载才交给父类加载器去加载。
Class<?> loadClass(String name, boolean resolve)
//将字节码转为类对象
Class<?> defineClass(String name, byte[] b, int off, int len)
findClass符合双亲委派机制,也是官方推荐使用的方式
loadClass不符合双亲委派,但是在一些特殊场合,如想让jvm中有多个相同的类,可以定义不同的加载器,每个加载器分别加载相同的类
重写classLoader一般直接继承ClassLoader,在loadClass/defineClass中填充defineClass字节码即可