Действительно ли путь к классу Java является окончательным после запуска JVM?

Я читал много о процессе загрузки класса Java в последнее время. Часто я сталкивался с текстами, которые утверждали, что не возможно добавить классы к пути к классу во время времени выполнения и загрузить их без хакерства загрузчика класса (URLClassLoaders и т.д.)

Насколько я знаю, что классы загружаются динамично. Это означает, что их представление байт-кода только загружается и преобразовывается к java.lang. Объект класса при необходимости.

Таким образом, разве не должно быть возможно добавить JAR или *.class файл к пути к классу после запущенной JVM и загрузить те классы, если они еще не были загружены? (Чтобы быть ясным: В этом случае путь к классу является просто папкой в файловой системе. "Добавление JAR или *.class файла" просто означает отбрасывать их в этой папке.)

И в противном случае который означает, что путь к классу ищется на запуске JVM, и все полностью определенные названия найденных классов кэшируются во внутреннем "списке"?

Было бы хорошо из Вас, если Вы могли бы указать на меня на некоторые источники в Ваших ответах. Предпочтительно официальная документация SUN: Sun Спецификация JVM. Я считал спецификацию, но ничего не мог найти о пути к классу и если это завершено на запуске JVM.

P.s.

Это - теоретический вопрос. Я просто хочу знать, возможно ли это. Нет ничего практического, которого я хочу достигнуть. Существует только моя жажда знания :)

22
задан Jens 31 May 2010 в 09:46
поделиться

5 ответов

Поскольку никто не смог дать мне однозначного ответа или ссылки на соответствующую часть документации, я отвечаю сам. Тем не менее, хочу поблагодарить всех, кто попытался ответить на этот вопрос.

Краткий ответ:

Путь к классам не является окончательным при запуске 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. Вы, очевидно, должны изменить это в зависимости от того, где вы размещаете классы.

Вот шаги, которые я выполнил:

  1. Убедитесь, что в jvmtest есть только JVMTest.class.
  2. Запустите программу командой сверху.
  3. Просто чтобы убедиться, нажмите Enter. Вы должны увидеть исключение, сообщающее, что класс не найден.
  4. Теперь запустите программу снова.
  5. После того, как программа запустится и вам будет предложено нажать клавишу ввода, скопируйте файл MyClass в папку jvmtest.
  6. Нажмите ввод. Вы должны увидеть «MyClass v1».

Дополнительные примечания:

Это также сработало, когда я упаковал класс 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)
6
ответ дан 29 November 2019 в 05:51
поделиться

Здесь смешиваются два понятия: classpath и файлы классов в classpath.

Если вы укажете classpath на каталог, у вас обычно не возникнет проблем с добавлением файла в каталог и его подхватом как части classpath. Из-за потенциального размера всех классов в classpath для современной JVM не представляется возможным загружать их все при запуске. Однако это имеет ограниченную ценность, поскольку не включает файлы Jar.

Однако изменение самого classpath (какие каталоги, банки и т.д. ищутся) на запущенной JVM будет сильно зависеть от реализации. Насколько я знаю, для стандартных JVM Sun не существует документированного (то есть гарантированно работающего) метода достижения этой цели.

В общем, если вам нужно сделать что-то подобное (иметь динамический classpath, который меняется во время выполнения), то вы хотите реализовать ClassLoader, хотя бы по той причине, чтобы иметь возможность выбросить его и создать новый, который больше не будет ссылаться на эти классы, если их нужно выгрузить.

Однако для небольшого объема динамической загрузки есть способы получше. В Java 1.6 вы можете указать все jar-файлы в каталоге (*.jar), так что вы можете сказать пользователям поместить дополнительные библиотеки в указанное место (хотя они должны быть там при запуске).

У вас также есть возможность включить jar-файл или другое место в classpath, даже если он вам не нужен, как место для размещения дополнительного jar-файла или файла ресурсов (например, файла конфигурации журнала).

Но если вам нужна серьезная динамическая загрузка и особенно выгрузка классов во время работы приложения, то требуется реализация Classloader.

6
ответ дан 29 November 2019 в 05:51
поделиться

Я могу комментировать только то, что помню из своего собственного опыта взлома не-Sun JVM десять лет назад, но она сканировала весь classpath при запуске, в качестве меры эффективности. Имена всех найденных классов добавлялись во внутреннюю хэш-таблицу вместе с их расположением (каталог или zip/jar файл). Однако это было десять лет назад, и я не могу не задаться вопросом, будет ли это все еще разумно делать в большинстве случаев, учитывая, как изменились архитектуры дисков и памяти.

0
ответ дан 29 November 2019 в 05:51
поделиться

Я считаю, что путь к классам считается статическим, а результат изменения файлов не определен.

Если вы действительно хотите иметь возможность добавлять и удалять классы во время выполнения, подумайте об этом в своем собственном загрузчике классов. Это то, что делают веб-контейнеры.

0
ответ дан 29 November 2019 в 05:51
поделиться

Значит, нельзя добавить JAR или * .class файл в путь к классам после запуска JVM ...

Вы добавляете jar-файлы и каталоги в путь к классам, а не классы. Классы находятся либо в каталоге, либо в банке.

А если нет, значит ли это, что путь к классам ищется при запуске JVM и все полные имена найденные классы кэшируются в внутренний «список»?

Это можно легко проверить: установите путь к классам, запустите вашу программу, переместите новый класс в CP, вызовите Class.forName («NewClass») из вашей программы. Нашел ли новый класс?

0
ответ дан 29 November 2019 в 05:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: