Работая на Java, мы часто используем большое количество классов. Они не загружаются все сразу в память, вместо этого загружаются, когда требуется приложением. Тогда и требуется ClassLoaders.
Что такое ClassLoader в Java?
ClassLoader в Java вызывается средой выполнения для динамической загрузки классов, когда это требуется приложением на виртуальной машине. Поскольку ClassLoaders являются частью Java Runtime Environment, виртуальная машина не будет иметь никакого представления о базовых файлах и файловых системах.
Типы
- Расширение (Extension ClassLoader).
- Приложение или Система (Application or System ClassLoader).
- Загрузчик (Bootstrap ClassLoader).
Расширение
Как следует из названия, загружает расширения основных классов Java из библиотеки расширений JDK. Он является дочерним элементом загрузчика Bootstrap ClassLoader и загружает расширения из каталога JRE / lib / text или любого другого каталога, указанного в системном свойстве java.ext.dirs.
Приложение или система
Является дочерним по отношению к Extension ClassLoader. Этот тип загружает все классы уровня приложения, найденные в параметре командной строки -cp или в переменной среды CLASSPATH.
Загрузчик
Как все мы знаем, что Java-классы загружаются экземпляром java.lang.ClassLoade. Но поскольку ClassLoaders являются классами, Bootstrap ClassLoader отвечает за загрузку внутренних классов JDK. По сути, это машинный код, который запускает операцию, когда JVM вызывает ее и загружает классы из rt.jar. Таким образом, вы можете понять, что служба Bootstrap ClassLoader не имеет родительского ClassLoader и поэтому известна как Primordial ClassLoader.
Примечание. Приоритет Bootstrap выше, чем Extension, а приоритет, присвоенный Extension ClassLoader, выше, чем Application ClassLoader. Обратитесь к изображению ниже:

Принципы
Набор правил, на основе которых работает ClassLoader, состоит из следующих трех принципов:
- Свойство уникальности.
- Модель делегирования.
- Принцип видимости.
Свойство уникальности
Это свойство гарантирует, что нет повторения классов, и все классы являются уникальными. Также гарантирует, что классы, загружаемые родительским ClassLoader, не загружаются дочерним. В сценарии, где родительский ClassLoader не может найти класс, текущий экземпляр попытается сделать это сам.
Модель делегирования
ClassLoader работает на основе набора операций, заданных моделью делегирования. Таким образом, всякий раз, когда генерируется запрос на поиск класса или ресурса, экземпляр ClassLoader делегирует поиск класса или ресурса родительскому ClassLoader.
Набор операций, на основе которых работает ClassLoader:
- Виртуальная машина проверяет, загружен ли класс или нет, всякий раз, когда он сталкивается с классом.
- В случае, когда класс загружен, JVM продолжает выполнение класса, но когда класс не загружен, JVM просит подсистему ClassLoader загрузить этот конкретный класс. После этого подсистема передает управление Application ClassLoader.
- Затем Application делегирует запрос Extension, которое затем передает запрос Bootstrap .
- Теперь Bootstrap ищет в пути Bootstrap classpath, чтобы проверить, доступен ли класс или нет. Если класс доступен, он загружается, в противном случае запрос снова передается в Extension.
- Extension проверяет класс в расширении classpath. Если класс доступен, он загружается, в противном случае запрос снова передается в Application.
- Наконец, Application ищет класс в пути к классам приложения. Если класс доступен, то загружается, иначе вы увидите исключение ClassNotFoundException.
Обратитесь к изображению ниже.

Принцип видимости
Согласно этому принципу, дочерние классы видны для классов, загруженных их родительскими ClassLoaders, но наоборот не соответствует действительности. Таким образом, классы, загруженные Application, имеют видимость классов, загруженных Extension и Bootstrap.
Например, если у нас есть два класса: A и B, предположим, что класс A загружается Application, а класс B загружается Extension. Здесь классы A и B видны всем тем классам, которые загружены Application, но класс B виден только тем классам, которые загружены Extension.
Кроме того, если вы попытаетесь загрузить эти классы с помощью Bootstrap ClassLoader, вы увидите java.lang.ClassNotFoundException исключение.
Методы
Вот несколько основных методов:
- loadClass (имя строки, логическое разрешение);
- defineClass();
- findClass (Строковое имя);
- Class.forName (имя строки, логическая инициализация, загрузчик ClassLoader);
- getParent();
- getResource().
loadClass()
Этот метод является точкой входа ClassLoader и используется для загрузки класса, на который ссылается JVM. Он принимает имя класса в качестве параметра. JVM вызывает метод loadClass() для разрешения ссылок на класс, устанавливая логическое значение true. Только если нам нужно определить, существует ли класс или нет, логический параметр имеет значение false.
Объявление:
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
defineClass()
Последний метод, используемый для определения массива байтов как экземпляра класса. В случае, если класс является недействительным, он выдает ClassFormatError.
Объявление:
protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError
findClass ()
Метод используется для поиска указанного класса. Таким образом, он просто находит класс с полностью определенным именем в качестве параметра, но не загружает его. Метод loadClass() вызывает этот метод, если родительский ClassLoader не может найти запрошенный класс. Кроме того, если ни один из родителей ClassLoader не находит класс, реализация по умолчанию генерирует исключение ClassNotFoundException.
Объявление:
protected Class<?> findClass(String name) throws ClassNotFoundException
Class.forName ()
Этот метод используется для загрузки и инициализации класса. Это дает возможность выбрать любой из ClassLoaders и в случае, если параметр ClassLoader равен NULL, тогда автоматически используется Bootstrap ClassLoader.
Объявление:
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)throws ClassNotFoundException
GetParent()
Метод getParent используется для возврата родительского ClassLoader для делегирования.
Объявление:
public final ClassLoader getParent()
getResource()
Метод getResource() пытается найти ресурс с заданным именем. Первоначально он делегирует запрос родительскому ClassLoader для ресурса. В случае, если родительский элемент является нулевым, ищется путь к ClassLoader, встроенному в JVM.
Теперь, если это не удается, тогда метод вызовет findResource (), чтобы найти ресурс, где имя ресурса указывается как вход, который может быть как абсолютным, так и относительным путем к классу. Затем он возвращает объект URL для чтения ресурса или возвращает нулевое значение, если у ресурса нет соответствующих прав для возврата ресурса или он не найден.
Объявление:
public URL getResource(String name)
Пользовательский ClassLoader в Java
Встроенные ClassLoaders позаботятся о большинстве случаев, когда файлы уже находятся в файловой системе, но если вы хотите загрузить классы с локального жесткого диска, вам нужно использовать пользовательские ClassLoaders.
Как создать
Чтобы создать, вам нужно расширить класс ClassLoader и переопределить метод findClass().
Пример: Давайте создадим собственный ClassLoader, который расширяет стандартный ClassLoader и загружает байтовый массив из указанного файла.
package edureka;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class Sample extends ClassLoader {
@Override
public Class findClass(String samplename) throws ClassNotFoundException {
byte[] b = customLoadClassFromFile(samplename);
return defineClass(samplename, b, 0, b.length);
}
private byte[] customLoadClassFromFile(String demofilename) {
InputStream inStream = getClass().getClassLoader().getResourceAsStream(
demofilename.replace('.', File.separatorChar) + ".class");
byte[] buffer;
ByteArrayOutputStream bStream = new ByteArrayOutputStream();
int nextValue = 0;
try {
while ( (nextValue = inStream.read()) != -1 ) {
bStream.write(nextValue);
}
} catch (IOException e) {
e.printStackTrace();
}
buffer = bStream.toByteArray();
return buffer;
}
}
