类加载的方式

主要有两种:

隐式加载:使用 new + 构造方法时,隐式的调用类加载器,加载对应的类到 JVM 中,是最常见的类加载方式。 显式加载:使用 loadClass()、forName() 等方法显式的加载需要的类,对于显式加载这种类加载方式来讲,当我们获取到了 Class 对象后,需要调用 Class 对象的 newInstance() 方法来生成对象的实例。

两种类加载方式的区别:

隐式加载能够直接获取对象的实例,而显式加载需要调用 Class 对象的 newInstance() 方法来生成对象的实例。 隐式加载能够使用有参的构造函数,而使用 Class 对象的 newInstance() 不支持传入参数,如果想使用有参的构造函数,必须通过反射的方式,来获取到该类的有参构造方法。

loadClass()和forName()的区别

  • 使用 loadClass() 方法获得的 Class 对象只完成了类加载过程中的第一步:加载,后续的操作均未进行。
  • 使用 Class.forName() 方法获得 Class 对象是已经执行完初始化的了

img

装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象;

链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

  校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)

  准备:给类的静态变量分配并初始化存储空间;

  解析:将常量池中的符号引用转成直接引用;

初始化:激活类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。

Class.forName(className)方法,内部实际调用的方法是 Class.forName(className,true,classloader); 第2个boolean参数表示类是否需要初始化, Class.forName(className)默认是需要初始化。 一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。

ClassLoader.loadClass(className)方法,内部实际调用的方法是 ClassLoader.loadClass(className,false); 第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接,由上面介绍可以, 不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行

备注:需要反射的时候获取静态方法变量的时候使用Class.forName(className)方法。