一、前言
在Java中,类加载器把一个类装入Java虚拟机中,要经过三步来完成:加载、连接和初始化,其中连接又分为验证、准备和解析三个阶段。加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段可以在初始化阶段之后发生,也称为动态绑定或晚期绑定。各个步骤的主要工作如下:
- 加载:查找和导入类或接口的二进制数据;
- 连接:又可以分成校验、准备和解析三步,其中解析步骤是可以选择的;
- 验证:检查导入类或接口的二进制数据的正确性;
- 准备:给类的静态变量分配并初始化存储空间;
- 解析:将符号引用转成直接引用;
- 初始化:激活类的静态变量的初始化Java代码和静态Java代码块。
而类加载的方式也有以下几种方式:
- 通过Class.forName()方法动态加载
- 通过ClassLoader.loadClass()方法
那么通过Class.forName()加载和通过ClassLoader.loadClass加载有啥区别呢?
二、分析
1、首先看下Class.forName()源码:
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
可以看到底层调用的forName0(className, true, ClassLoader.getClassLoader(caller), caller),第二个参数initialize表示是否执行类中的静态代码块、对类中的静态变量赋值等初始化操作,默认给的true。
2、在Class类中还有另一个方法,可以自己传入initialize的值,源码如下:
/**
* @param name fully qualified name of the desired class
* @param initialize if {@code true} the class will be initialized.
* See Section 12.4 of <em>The Java Language Specification</em>.
* @param loader class loader from which the class must be loaded
* @return class object representing the desired class
*
* @exception LinkageError if the linkage fails
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails
* @exception ClassNotFoundException if the class cannot be located by
* the specified class loader
*
* @see java.lang.Class#forName(String)
* @see java.lang.ClassLoader
* @since 1.2
*/
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null)