一、Java加载类
在类加载器中,有三种方式可以实现类的加载。
- 1.通过命令行启动应用时由 JVM 初始化加载,在上文已提及过
- 2.通过
Class.forName()
方法动态加载 - 3.通过
ClassLoader.loadClass()
方法动态加载
其中Class.forName()
和ClassLoader.loadClass()
加载方法,稍有区别:
Class.forName()
:表示将类的.class
文件加载到 JVM 中之后,还会对类进行解释,执行类中的static
方法块;Class.forName(name, initialize, loader)
:支持通过参数来控制是否执行类中的static
方法块;ClassLoader.loadClass()
:它只将类的.class
文件加载到 JVM,但是不执行类中的static
方法块,只有在newInstance()
才会去执行static
方法块;
我们可以看一个简单的例子!
public class ClassTest {
static {
System.out.println("初始化静态代码块!");
}
}
public class CustomClassLoaderTest {
public static void main(String[] args) throws Exception {
// 获取当前系统类加载器
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 1.使用Class.forName()来加载类,默认会执行初始化静态代码块
Class.forName(ClassTest.class.getName());
// 2.使用Class.forName()来加载类,指定false,不会执行初始化静态代码块
// Class.forName(ClassTest.class.getName(), false, classLoader);
// 3.使用ClassLoader.loadClass()来加载类,不会执行初始化静态代码块
// classLoader.loadClass(ClassTest.class.getName());
}
}
运行结果如下:
初始化静态代码块!
切换不同的加载方式,会有不同的输出结果!
二、Java加载类的总结
从以上的介绍中,针对类加载器的机制,我们可以总结出以下几点:
- 全盘负责:当一个类加载器负责加载某个
Class
文件时,该Class
所依赖的和引用的其他Class
也将由该类加载器负责载入,除非显示使用另外一个类加载器来加载 - 双亲委派:在接受类加载请求时,会让父类加载器试图加载该类,只有在父类加载器无法加载该类或者没有父类时,才尝试从自己的类路径中加载该类
- 按需加载:用户创建的类,通常加载是按需进行的,只有使用了才会被类加载器加载
- 缓存机制:有被加载过的
Class
文件都会被缓存,当要使用某个Class
时,会先去缓存查找,如果缓存中没有才会读取Class
文件进行加载。这就是为什么修改了Class
文件后,必须重启 JVM,程序的修改才会生效的原因。