Сравнение Class.forName и ClassLoader.loadClass

Java

1. Введение

Жизненный цикл класса, разделенный назагрузить, подключить (проверить, подготовить, проанализировать), инициализировать, использовать, выгрузитьэти процессы.

Class.forNameа такжеClassLoader.loadClassбудет выполнятьнагрузкаПроцедура, которая загружает указанный класс в память для использования.

Но после загрузки по умолчанию:Class.forNameвстречаинициализация,ClassLoader.loadClassНичего не делает после загрузки.

2 Class.forName

java.lang.Classесть дваforNameМетод, параметры разные, все вызывают приватный методforName0:

private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class<?> caller) throws ClassNotFoundException;

параметр:

  • name: полное имя класса
  • initialize: Инициализировать ли
  • loader: использовать загрузчик классов
  • caller: класс вызывающего абонента

вернуть: Класс с полным именем загружается с помощью загрузчика

  • forName(String className)
  • forName(String name, boolean initialize, ClassLoader loader)

2.1 Укажите только className

public static Class<?> forName(String className)
                throws ClassNotFoundException {
        // 获取调用者的类
        Class<?> caller = Reflection.getCallerClass();
        // 使用调用者的调用者的ClassLoader加载,加载后对类进行初始化。
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

2.2 Одновременно укажите ClassLoader

    public static Class<?> forName(String name, boolean initialize,
                                   ClassLoader loader)
        throws ClassNotFoundException
    {
        Class<?> caller = null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
             //有SecurityManager时,才需要获取调用者的类。
            caller = Reflection.getCallerClass();
            if (sun.misc.VM.isSystemDomainLoader(loader)) {
                ClassLoader ccl = ClassLoader.getClassLoader(caller);
                if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                    sm.checkPermission(
                        SecurityConstants.GET_CLASSLOADER_PERMISSION);
                }
            }
        }
        // 指定类全名,是否初始化,ClassLoader,调用者的类 调用forName0
        return forName0(name, initialize, loader, caller);
    }

3 ClassLoader.loadClass

параметр:

  • name: полное имя класса
  • resolve: Соединительная часть жизненного цикла выполняется после загрузки

вернуть: Класс с полным именем загружается с использованием текущего ClassLoader.

обработать:

  • 1 звонокfindLoadedClass(name)Проверяем, загрузился ли класс, если нет, продолжаем;
  • 2 родителя существует, в соответствии с моделью родительского делегирования, вызовparent.loadClass(name, false), сначала выполнить loadClass из родителя (но не подключаться);
  • 3 родитель не существует, затем вызовитеfindBootstrapClassOrNull(name)Определите, был ли он загружен в Bootstrap Classloader;
  • 4 Если класс по-прежнему не найден, выполните findClass, чтобы найти класс, а findClass реализуется подклассом ClassLoader, напримерjava.net.URLClassLoader;
  • 5 Наконец, согласноresolveпараметр, чтобы определить, выполнять ли соединение.
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 检查类是否已经加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 双亲委派,优先从parent中执行loadClass,但执行时,不进行连接。
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    // name是否在Bootstrap Classloader中加载过,是的话则返回该类。
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    
                    // 执行findClass查找类,findClass由ClassLoader的子类实现。
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                // 执行连接操作
                resolveClass(c);
            }
            return c;
        }
    }

Также есть метод loadClass без разрешения в ClassLoader, который не выполняет подключение после загрузки класса:

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

4 Резюме

И Class.forName, и ClassLoader.loadClass выполняют процесс загрузки. Отличие в том, что в классенагрузкаЗадний:

  • Class.forName: выполнение по умолчаниюинициализация, но могу указать;
  • ClassLoader.loadClass: ничего не делать по умолчанию (не подключен, не инициализирован), но вы можете указать,соединять.