ClassLoader学习.md

用途

读取.class文件的字节码并加载成内存形式的类对象。

边解释边执行

JVM并不是一次性加载全部的类,而是需要用到才会去加载。比如加载了类,但是不会去加载类里面定义的对象类型的字段的类,因为暂时用不到。

Java内置的ClassLoader

ClassLoader的选择

当我们定义一个ClassLoader,其内部都包含了一个ClassLoader,当遇到未知的类,JVM会选择调用者自己的ClassLoader去加载。

那么最初的调用者一定是持有main()方法的类,他持有的是AppClassLoader

双亲委派

AppClassLoader只负责加载Classpath下面的类秒如果遇到没有加载过的系统类,他会将系统类库的加载工作交给BootstrapClassLoaderExtensionClassLoader来做,这就叫双亲委派

每个ClassLoader中都有一个parent属性指向父级,然后会优先让父级去加载,若父级加载失败,才轮到自己去加载:

AppClassLoader -> ExtensionClassLoader -> BootstrapClassLoader

ExtensionClassLoader的parent的值为null,只要是parent=null的,说明父加载器就是BootstrapClassLoader。

使用ClassLoader

Class.forName

1
2
3
Class.forName("com.mysql.cj.jdbc.Driver");

Class<?> forName(String name, boolean initialize, ClassLoader cl)

这个方法默认使用“调用者”的ClassLoader来加载目标类,并且可以选择其他的ClassLoader。

ClassLoader.loadClass

1
ClassLoader.getSystemClassLoader().loadClass("[I");

使用

使用时一般都会结合反射。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Class<?> clazz1 = App.class.getClassLoader().loadClass("Student");
Class<?> clazz2 = Student.class.getClassLoader().loadClass("Student");
Class<?> clazz3 = ClassLoader.getSystemClassLoader().loadClass("Student");
Class<?> clazz4 = Class.forName("Student");


Object obj1 = clazz1.getConstructor().newInstance();
clazz1.getMethods()[0].invoke(obj1, "obj1");

Object obj2 = clazz2.getConstructor().newInstance();
clazz1.getMethods()[0].invoke(obj2, "obj2");

Object obj3 = clazz3.getConstructor().newInstance();
clazz1.getMethods()[0].invoke(obj3, "obj3");

Object obj4 = clazz4.getConstructor().newInstance();
clazz1.getMethods()[0].invoke(obj4, "obj4");

自定义类加载器

ClassLoader 里面有三个重要的方法 loadClass()、findClass() 和 defineClass()。