Class.forName() 与 ClassLoader.loadClass() 的区别
说明
- @author JellyfishMIX - github / blog.jellyfishmix.com
- LICENSE GPL-2.0
介绍
Class.forName() 与 ClassLoader.loadClass() 这两种方式可以动态加载一个类,区别是:
- Class.forName() 的方式加载类时,默认会执行类的初始化。
- ClassLoader.loadClass() 的方式加载类时,类不会被初始化,只有显式调用加载的类时才会进行初始化。采用 ClassLoader 进行懒加载,不会调用类的 static 代码块,实现延迟加载。
demo 演示
demo 演示上述介绍。
ClassLoadTest
public class ClassLoadTest {
public static void main(String[] args) throws ClassNotFoundException {
System.out.println("Class.forName 方式加载类--->start");
Class.forName("classtest.classloader.MyClassForName").getClass();
System.out.println("Class.forName 方式加载类--->end");
System.out.println("ClassLoader 方式加载类--->start");
Class<?> bClass = ClassLoader.getSystemClassLoader().loadClass("classtest.classloader.MyClassLoader");
System.out.println("ClassLoader 方式加载类--->end");
}
}
MyClassForName
public class MyClassForName {
static {
System.out.println("MyClassForName static method execute");
}
}
MyClassLoader
public class MyClassLoader {
static {
System.out.println("MyClassLoader static method execute");
}
}
运行结果
运行结果符合预期。
Class.forName 方式加载类--->start
MyClassForName static method execute
Class.forName 方式加载类--->end
ClassLoader 方式加载类--->start
ClassLoader 方式加载类--->end
Class.forName()
- 将一个类加载到内存中。
- 类默认会被初始化(initialize 这个参数传的是 true),执行内部的静态块代码和保证静态属性被初始化。
- 默认会使用当前的 ClassLoader 来加载指定的类。
ClassLoader.loadClass()
ClassLoader 的双亲委派模型就不提了。
- ClassLoader.loadClass() 的方式加载类时,类不会被初始化,只有显式调用加载的类时才会进行初始化。
- 将一个 java 类加载到内存中,类不会被初始化,只有显式使用加载的类时才会进行初始化。因为虚拟机规范规定了,当遇到 new, getstatic, putstatic, invokestatic 这 4 条字节码指令时,如果没有进行过初始化则需要先触发初始化。
- 采用 ClassLoader 进行懒加载,不会调用类的 static 代码块,实现延迟加载。
类的显示使用
当一个类被显示使用时,JVM 会对其进行初始化,如下六种情况为显示使用:
- 当创建某个类的新实例时(如通过 new 或反射,克隆,反序列化等)。
- 当调用某个类的静态方法时。
- 当使用某个类或接口的静态字段时。
- 当调用某些反射方法时,比如类 Class 中的方法,或者 java.lang.reflect 中的类的方法时。
- 当初始化某个子类时。
- 当 JVM 启动某个被标明为启动类的类(即包含 main 方法的那个类)。