Java 类的加载方式

类的加载方式

类的加载方式

  1. 隐式加载
  2. 显式加载

隐式加载有几种情况:

  1. 首次通过 new 创建一个类的实例
  2. 首次调用类的静态成员
  3. 首次加载一个类,会先加载它的父类
  4. JVM 启动时,会自动加载定义了 main 方法的类

显式加载有两种方式:

  1. 通过 ClassLoader.loadClass
  2. 通过 Class.forName

区别

隐式加载是在首次使用时才加载类,显式加载是先提前加载类再使用。

显式加载用于实现反射特性,其主要步骤为:

  1. 加载 *.class 字节码文件获取 Class 对象
  2. 通过 Class 对象获取构造器
  3. 调用 newInstance 方法创建对象实例
import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) {
        try {
            // 1. 加载 *.class 字节码文件获取 Class 对象
            Class<?> c = Class.forName("A");
            // Class<?> c = ClassLoader.getSystemClassLoader().loadClass("A");

            // 2. 通过 Class 对象获取构造器
            Constructor<?> cons = c.getConstructor();

            // 3. 调用 newInstance 方法创建对象实例
            A a = (A) cons.newInstance();
            a.hello();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class A {
    public A() {
        System.out.println("调用无参构造函数");
    }
    public void hello() {
        System.out.println("hello");
    }
}

ClassLoader.loadClass 和 Class.forName 加载类的区别

类的装载包括 3 个步骤:加载(loading),链接(link),初始化(initialize)。

Class.forName

forName0 第二个参数 initialize 决定是否初始化,这里参数是 true 说明是准备初始化。因此,静态代码快和静态变量是会被执行和初始化的。

    @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

    /** 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;

注意: Class.forName 实际上也是借助了 ClassLoader 加载类的。

ClassLoader.loadClass

第二参数 resolve,注释中说明这个参数代表是否链接,即类加载过程中的链接过程。这里,ClassLoader.loadClass 在加载类的过程中只走了第一步。

    @CallerSensitive
    public static ClassLoader getSystemClassLoader() {
        // ...
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        // ...
    }

总结

  • Class.forName 加载的类已经初始化了。
  • ClassLoader.loadeClass 加载的类只是加载了,还没有进行链接。
发布了147 篇原创文章 · 获赞 72 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Pranuts_/article/details/101752480