Difference Class.forName () and ClassLoader.loadClass () of

    See a face questions, talk about the Class.forName () and ClassLoader.loadClass () different, specially recorded it for easy later retrieval.
     When we write java code, usually two ways to dynamically load a java class, they are Class.forName () and ClassLoader.loadClass (). But there are also subtle differences between these two methods, let's look at the results of the practice by writing code that way.

A, Class.forName () mode

(1) theory

    See Class class code embodied inside understood, this is essentially native method is called as follows:
       /** Called after security check for system loader access checks have been made. */
    private static native Class<?> forName0(String name, boolean initialize,
                                            ClassLoader loader,
                                            Class<?> caller)throws ClassNotFoundException;
          Similar in form to Class.forName (name, true, currentLoader). In summary, Class.forName If the call is successful:
      • It will give a valid Java class is loaded into memory;
      • The default class is initialized (initialize this parameter passed is true), i.e., a static block code is performed inside the static properties and to ensure initialized;
      • Use the current default class loader to load the corresponding class.

(2) Code Description

          Be described below with Code
          Reference Code:
public class TestClass {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("Class.forName 方式加载类--->start");
        Class.forName("com.jwx.digital.client.AClass").getClass();
        System.out.println("Class.forName 方式加载类--->end");
    }
}

class AClass {
    static {
        System.out.println("AClass初始化");
        System.out.println("=====AClass静态代码快执行=====");
    }
}
    operation result:
Class.forName 方式加载类--->start
AClass初始化
=====AClass静态代码快执行=====
Class.forName 方式加载类--->end

Two, ClassLoader.loadClass way

(1) theory

          In this way the class loading strategy, due to the presence of parents delegate model, will eventually be delivered to load tasks like loading to Bootstrap ClassLoader. Tracking the source code, it will eventually call the native method:
    // return null if not found
    private native Class<?> findBootstrapClass(String name);
          与此同时,与Class.forName()方式的最本质的不同是,类不会被初始化,只有显式调用才会进行初始化。综上所述,ClassLoader.loadClass 如果调用成功后:
      • 将一个java类加载到内存中;
      • 类不会被初始化,只有在之后被第一次调用时类才会被初始化;因为虚拟机规范规定了,当遇到new、getstatic、putstatic或invokestatic这4条字节码指令是,如果没有进行过初始化则需要先触发初始化。

(2)代码说明

      下面通过代码来说明
          参考代码:
public class TestClass {
    public static void main(String[] args) throws Exception {
        System.out.println("ClassLoader 方式加载类--->start");
        Class<?> aClass = ClassLoader.getSystemClassLoader().loadClass("com.jwx.digital.client.AClass");
        System.out.println("ClassLoader 方式加载类--->end");
        /* 虽然上面没有进行类的初始化,
         但是虚拟机规范规定了,当遇到new、getstatic、putstatic或invokestatic这4条字节码指令是,如果没有进行过初始化则需要先触发初始化。
         生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、
         读取或者设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。*/
        // 因此我们实例化这个class时,就会调用初始化
        System.out.println("我要实例化这个类了+++++");
        aClass.newInstance();
    }
}

class AClass {
    static {
        System.out.println("AClass初始化");
        System.out.println("=====AClass静态代码快执行=====");
    }
}
    运行结果:
ClassLoader 方式加载类--->start
ClassLoader 方式加载类--->end
我要实例化这个类了+++++
AClass初始化
=====AClass静态代码快执行=====

三、总结

    (1)Class.forName的形式加载类时,默认会执行类的初始化
    (2)ClassLoader.loadClass的方式加载类时, 类不会被初始化,只有显式调用才会进行初始化。可以用来延迟加载(采用ClassLoader进行懒加载,就不会调用类的静态代码快,实现延迟加载)

四、补充

 当一个类被主动使用时,Java虚拟机就会对其初始化,如下六种情况为主动使用

    1. 当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
    2. 当调用某个类的静态方法时
    3. 当使用某个类或接口的静态字段时
    4. 当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时
    5. 当初始化某个子类时
    6. 当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)




Guess you like

Origin www.cnblogs.com/zeng1994/p/81976a2ea470861e34a4223b7561a970.html