Ответ 1
Взято из этого приятного учебника от Sun:
Мотивация
Приложения, написанные на статически скомпилированных языках программирования, такие как C и С++, скомпилированы в собственные инструкции, определенные машиной, и сохраняются как исполняемый файл. Процесс объединения кода в исполняемый собственный код называется linking - слияние отдельно скомпилированного кода с кодом общей библиотеки для создания исполняемого приложения. Это отличается от динамически скомпилированных языков программирования, таких как Java. В Java файлы .class, сгенерированные компилятором Java, остаются как есть до загрузки в виртуальную машину Java (JVM) - другими словами, процесс связывания выполняется JVM во время выполнения. Классы загружаются в JVM по принципу "по мере необходимости". И когда загруженный класс зависит от другого класса, этот класс также загружается.
При запуске приложения Java первый класс, который запускается (или точка входа в приложение), является тем, у кого есть открытый метод static void, называемый main(). Этот класс обычно имеет ссылки на другие классы, и все попытки загрузить ссылочные классы выполняются загрузчиком классов.
Чтобы получить ощущение этой рекурсивной загрузки классов, а также идею загрузки класса в целом, рассмотрим следующий простой класс:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
Если вы запустите этот класс, указав параметр командной строки -verbose: class, чтобы он печатал, какие классы загружаются, вы получите результат, который выглядит следующим образом. Обратите внимание, что это всего лишь частичный вывод, так как список слишком длинный, чтобы показать здесь.
prmpt>java -verbose:class HelloApp
[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
Как вы можете видеть, сначала загружаются классы времени выполнения Java, требуемые классом приложения (HelloApp).
Погрузчики классов на платформе Java 2
Язык программирования Java продолжает развиваться, чтобы сделать жизнь разработчиков приложений проще каждый день. Это делается путем предоставления API-интерфейсов, которые упрощают вашу жизнь, позволяя вам сосредоточиться на бизнес-логике, а не на деталях реализации основных механизмов. Это видно из недавнего изменения J2SE 1.5 до J2SE 5.0, чтобы отразить зрелость платформы Java.
Как и в JDK 1.2, загрузчик классов bootstrap, встроенный в JVM, отвечает за загрузку классов среды выполнения Java. Этот загрузчик классов загружает только классы, которые находятся в пути к загрузке, и поскольку это доверенные классы, процесс проверки не выполняется как для ненадежных классов. В дополнение к загрузчику класса bootstrap JVM имеет загрузчик классов расширения, отвечающий за загрузку классов из стандартных API расширений, и загрузчик системного класса, который загружает классы из общего пути класса, а также для ваших классов приложений.
Так как существует более одного класса загрузчика, они представлены в дереве, корнем которого является загрузчик класса начальной загрузки. У каждого загрузчика классов есть ссылка на его загрузчик родительского класса. Когда загрузчик класса запрашивает загрузку класса, он советуется с его загрузчиком родительского класса, прежде чем пытаться загрузить сам элемент. Родитель, в свою очередь, консультируется со своим родителем и так далее. Таким образом, только после того, как все загрузчики классов предков не смогут найти класс, к которому относится текущий загрузчик классов. Другими словами, используется модель делегирования.
Класс java.lang.ClassLoader
java.lang.ClassLoader
- это абстрактный класс, который может быть подклассифицирован приложениями, которые должны расширять способ, с помощью которого JVM динамически загружает классы. Конструкторы в java.lang.ClassLoader
(и его подклассы) позволяют указать родителя при создании экземпляра нового загрузчика классов. Если вы явно не укажете родителя, загрузчик системного класса виртуальной машины будет назначен как родитель по умолчанию. Другими словами, класс ClassLoader использует модель делегирования для поиска классов и ресурсов. Поэтому каждый экземпляр класса ClassLoader имеет связанный родительский загрузчик классов, поэтому при запросе поиска класса или ресурсов задача делегируется загрузчику родительского класса, прежде чем пытаться найти сам класс или ресурс. Метод loadClass()
класса ClassLoader выполняет следующие задачи, чтобы при вызове загрузить класс:
Если класс уже загружен, он возвращает его.
В противном случае он делегирует поиск нового класса загрузчику родительского класса.
Если загрузчик родительского класса не находит класс, loadClass()
вызывает метод findClass()
для поиска и загрузки класса.
Метод finalClass()
ищет класс в текущем загрузчике классов, если класс не был найден загрузчиком родительского класса.
В оригинальной статье больше, в которой также показано, как реализовать свои собственные загрузчики сетевого класса, что отвечает на ваш вопрос о том, почему (и как). См. Также API-документы.