Я читал много о процессе загрузки класса Java в последнее время. Часто я сталкивался с текстами, которые утверждали, что не возможно добавить классы к пути к классу во время времени выполнения и загрузить их без хакерства загрузчика класса (URLClassLoaders и т.д.)
Насколько я знаю, что классы загружаются динамично. Это означает, что их представление байт-кода только загружается и преобразовывается к java.lang. Объект класса при необходимости.
Таким образом, разве не должно быть возможно добавить JAR или *.class файл к пути к классу после запущенной JVM и загрузить те классы, если они еще не были загружены? (Чтобы быть ясным: В этом случае путь к классу является просто папкой в файловой системе. "Добавление JAR или *.class файла" просто означает отбрасывать их в этой папке.)
И в противном случае который означает, что путь к классу ищется на запуске JVM, и все полностью определенные названия найденных классов кэшируются во внутреннем "списке"?
Было бы хорошо из Вас, если Вы могли бы указать на меня на некоторые источники в Ваших ответах. Предпочтительно официальная документация SUN: Sun Спецификация JVM. Я считал спецификацию, но ничего не мог найти о пути к классу и если это завершено на запуске JVM.
P.s.
Это - теоретический вопрос. Я просто хочу знать, возможно ли это. Нет ничего практического, которого я хочу достигнуть. Существует только моя жажда знания :)
Поскольку никто не смог дать мне однозначного ответа или ссылки на соответствующую часть документации, я отвечаю сам. Тем не менее, хочу поблагодарить всех, кто попытался ответить на этот вопрос.
Краткий ответ:
Путь к классам не является окончательным при запуске JVM.
Фактически вы можете поместить классы в путь к классам после запуска JVM, и они будут загружены.
Длинный ответ:
Чтобы ответить на этот вопрос, я последовал предложению неизвестных пользователей и написал небольшую тестовую программу.
Основная идея состоит в том, чтобы иметь два класса. Один из них - это основной класс, который создает экземпляр второго класса. При запуске второй класс отсутствует в пути к классам. После запуска программы cli вам будет предложено нажать клавишу ввода. Перед тем, как нажать Enter, вы копируете второй класс в путь к классам. После нажатия клавиши ввода создается экземпляр второго класса. Если путь к классам будет окончательным при запуске JVM, это вызовет исключение. Но это не так. Поэтому я предполагаю, что путь к классам не является окончательным при запуске JVM.
Вот исходные коды:
JVMTest.java
package jvmtest;
import java.io.Console;
import jvmtest.MyClass;
public class JVMTest {
public static void main(String[] args) {
System.out.println("JVMTest started ...");
Console c = System.console();
String enter = c.readLine("Press Enter to proceed");
MyClass myClass = new MyClass();
System.out.println("Bye Bye");
}
}
MyClass.java
package jvmtest;
public class MyClass {
public MyClass() {
System.out.println("MyClass v2");
}
}
Структура папок выглядит так:
jvmtest/
JVMTest.class
MyClass.class
Я запустил программу cli с помощью этой команды:
> java -cp /tmp/ jvmtest.JVMTest
Как видите, моя папка jvmtest находилась в / tmp / jvmtest. Вы, очевидно, должны изменить это в зависимости от того, где вы размещаете классы.
Вот шаги, которые я выполнил:
Дополнительные примечания:
Это также сработало, когда я упаковал класс MyClass в банку и запустил тест, описанный выше.
Я запускал это на своем Macbook Pro под управлением Mac OS X 10.6.3
> Java -version
результаты:
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
Здесь смешиваются два понятия: classpath и файлы классов в classpath.
Если вы укажете classpath на каталог, у вас обычно не возникнет проблем с добавлением файла в каталог и его подхватом как части classpath. Из-за потенциального размера всех классов в classpath для современной JVM не представляется возможным загружать их все при запуске. Однако это имеет ограниченную ценность, поскольку не включает файлы Jar.
Однако изменение самого classpath (какие каталоги, банки и т.д. ищутся) на запущенной JVM будет сильно зависеть от реализации. Насколько я знаю, для стандартных JVM Sun не существует документированного (то есть гарантированно работающего) метода достижения этой цели.
В общем, если вам нужно сделать что-то подобное (иметь динамический classpath, который меняется во время выполнения), то вы хотите реализовать ClassLoader, хотя бы по той причине, чтобы иметь возможность выбросить его и создать новый, который больше не будет ссылаться на эти классы, если их нужно выгрузить.
Однако для небольшого объема динамической загрузки есть способы получше. В Java 1.6 вы можете указать все jar-файлы в каталоге (*.jar), так что вы можете сказать пользователям поместить дополнительные библиотеки в указанное место (хотя они должны быть там при запуске).
У вас также есть возможность включить jar-файл или другое место в classpath, даже если он вам не нужен, как место для размещения дополнительного jar-файла или файла ресурсов (например, файла конфигурации журнала).
Но если вам нужна серьезная динамическая загрузка и особенно выгрузка классов во время работы приложения, то требуется реализация Classloader.
Я могу комментировать только то, что помню из своего собственного опыта взлома не-Sun JVM десять лет назад, но она сканировала весь classpath при запуске, в качестве меры эффективности. Имена всех найденных классов добавлялись во внутреннюю хэш-таблицу вместе с их расположением (каталог или zip/jar файл). Однако это было десять лет назад, и я не могу не задаться вопросом, будет ли это все еще разумно делать в большинстве случаев, учитывая, как изменились архитектуры дисков и памяти.
Я считаю, что путь к классам считается статическим, а результат изменения файлов не определен.
Если вы действительно хотите иметь возможность добавлять и удалять классы во время выполнения, подумайте об этом в своем собственном загрузчике классов. Это то, что делают веб-контейнеры.
Значит, нельзя добавить JAR или * .class файл в путь к классам после запуска JVM ...
Вы добавляете jar-файлы и каталоги в путь к классам, а не классы. Классы находятся либо в каталоге, либо в банке.
А если нет, значит ли это, что путь к классам ищется при запуске JVM и все полные имена найденные классы кэшируются в внутренний «список»?
Это можно легко проверить: установите путь к классам, запустите вашу программу, переместите новый класс в CP, вызовите Class.forName («NewClass») из вашей программы. Нашел ли новый класс?