Взято из этого хорошего урока от Sun:
мотивация
Приложения, написанные на статически скомпилированных языках программирования, таких как C и C ++, компилируются в собственные, машинно-зависимые инструкции и сохраняются в виде исполняемого файла. Процесс объединения кода в исполняемый собственный код называется связыванием - объединением отдельно скомпилированного кода с кодом общей библиотеки для создания исполняемого приложения. Это отличается в динамически скомпилированных языках программирования, таких как Java. В Java файлы .class, сгенерированные компилятором Java, остаются как есть до тех пор, пока не будут загружены в виртуальную машину Java (JVM) - другими словами, процесс связывания выполняется JVM во время выполнения. Классы загружаются в JVM по мере необходимости. И когда загруженный класс зависит от другого класса, тогда этот класс также загружается.
Когда Java-приложение запускается, первый класс для запуска (или точка входа в приложение) - это класс с открытым статическим методом 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 загрузчик классов начальной загрузки, встроенный в JVM, отвечает за загрузку классов среды выполнения Java. Этот загрузчик классов загружает только те классы, которые находятся в загрузочном пути к классам, и, поскольку это доверенные классы, процесс проверки не выполняется, как для ненадежных классов. В дополнение к загрузчику классов начальной загрузки JVM имеет загрузчик классов расширений, отвечающий за загрузку классов из стандартных API расширений, и загрузчик системных классов, который загружает классы из общего пути классов, а также классы вашего приложения.
Поскольку имеется более одного загрузчика классов, они представлены в дереве, корнем которого является загрузчик классов начальной загрузки. Каждый загрузчик классов имеет ссылку на свой родительский загрузчик классов. Когда загрузчику класса предлагается загрузить класс, он обращается к своему загрузчику родительского класса, прежде чем пытаться загрузить сам элемент. Родитель, в свою очередь, консультируется со своим родителем и так далее. Таким образом, только после того, как все загрузчики класса-предка не могут найти класс, текущий загрузчик класса подключается. Другими словами, используется модель делегирования.
Класс java.lang.ClassLoader
Это java.lang.ClassLoader
абстрактный класс, который может быть разделен на подклассы приложениями, которым необходимо расширить способ динамической загрузки классов JVM. Конструкторы в java.lang.ClassLoader
(и его подклассах) позволяют вам указывать родителя, когда вы создаете новый загрузчик классов. Если вы не укажете явно родительский объект, загрузчик системного класса виртуальной машины будет назначен родительским по умолчанию. Другими словами, класс ClassLoader использует модель делегирования для поиска классов и ресурсов. Таким образом, каждый экземпляр ClassLoader имеет связанный родительский загрузчик классов, поэтому при запросе на поиск класса или ресурсов задача делегируется его родительскому загрузчику классов перед попыткой найти сам класс или ресурс. loadClass()
Метод ClassLoader выполняет следующие задачи, для того, когда вызывается для загрузки класса:
Если класс уже загружен, он возвращает его. В противном случае он делегирует поиск нового класса загрузчику родительского класса. Если загрузчик родительского класса не находит класс, loadClass()
вызывает метод findClass()
для поиска и загрузки класса. В finalClass()
поисках метода для класса в текущем загрузчике класса , если класс не был найдены родительским загрузчиком классов.
В исходной статье есть еще кое-что, в котором также показано, как реализовать собственные загрузчики сетевых классов, и ответ на ваш вопрос, почему (и как). Смотрите также документы API .