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: ничего не делать по умолчанию (не подключен, не инициализирован), но вы можете указать,соединять.