Подтвердить что ты не робот

Является ли загрузчик классов Java гарантией не загружать классы, которые не используются?

Есть ли гарантия, что загрузчик классов Java по умолчанию, по умолчанию, система не пытается загружать классы, которые не указаны в запущенном коде? Несколько примеров того, что я имею в виду:

  • Я использую framework.jar, который, как я знаю, содержит ссылки на другие классы library.jar, но я использую только такую ​​часть фреймворка, которая не содержит этих ссылок. Можно ли оставить library.jar вне?
  • Статические блоки запускаются при первом загрузке класса. Если какой-либо код не содержит ссылки на определенный класс, уверен ли он, что статический блок не запущен?

Быстрое тестирование, похоже, работает так, как предполагалось выше, и в любом случае не имеет смысла загружать неиспользуемые классы, но есть ли какие-либо гарантии на это?

Дополнение: Кажется, что мои "статические блоки запускаются при первом загрузке класса" выше, это несколько неверно. Конечно, можно загружать классы (одно) без их запуска (другое). Поэтому меня интересуют оба случая; гарантирует, что классы не загружаются, а не запускаются.

4b9b3361

Ответ 1

Нет такой гарантии 1 по загрузке классов.

Однако вам гарантировано, что статические блоки не будут запущены преждевременно. События, инициирующие инициализацию классов, указаны в JLS 12.4.1.

Класс или тип интерфейса T будет инициализирован непосредственно перед первым вхождением любого из следующих значений:

  • T - это класс и создается экземпляр T.
  • T - класс, и статический метод, объявленный T, вызывается.
  • Назначено статическое поле, объявленное T.
  • Используется статическое поле, объявленное T, и поле не является постоянной переменной (§4.12.4).
  • T - класс верхнего уровня, и выполняется инструкция assert (§14.10), лексически вложенная в T.

1 - Наблюдается, что существующие Java-реализации поколения не загружают классы без необходимости, но это не гарантия. Единственные гарантии - это то, что он написал в официальных спецификациях.

Ответ 2

java спецификация утверждает

Процесс загрузки реализуется класс ClassLoader и его подклассы. Различные подклассы ClassLoader может политики загрузки. В частности, загрузчик классов может кэш-двоичные представления классы и интерфейсы, предварите их на основе ожидаемого использования, или загрузить группа связанных классов вместе.

Таким образом, загрузчик классов может предварительно выбирать классные файлы.

Класс или тип интерфейса T будет инициализируется непосредственно перед первое появление любого из следующее:

  • T - это класс и создается экземпляр T.
  • T - класс, и статический метод, объявленный T, вызывается.
  • Назначено статическое поле, объявленное T.
  • Используется статическое поле, объявленное T, и ссылка на поле не является константой времени компиляции (§15.28). Ссылки на константы времени компиляции должны быть разрешены во время компиляции до копии значения постоянной времени компиляции, поэтому использование такого поля никогда не вызывает инициализации.

Статические блоки будут выполняться только при первом использовании класса.

Ответ 3

Я не думаю, что есть такая гарантия. Во-первых, я видел сканеры кода, которые обрабатывают аннотации из целых иерархий пакетов /JAR во время запуска приложения; они сразу нарушат это предположение.

Почему это имеет значение? Вы, как правило, после очень контролируемой загрузки системы, чтобы все, что было бы важно, было бы где-то там, где вы все равно должны были бы заставить его...

Ответ 4

Вещь, которая тянет в классах, это ссылки на них из байтового кода Java (который снова может вызывать другие классы). Если классы, которые вы запускаете, не имеют ссылки на класс X, он не будет загружен.

Обратите внимание, однако, что существуют новые способы регистрации, например. услуг через META-INF. Эти классы также должны быть загружены.

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

Ответ 5

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

Если ваш код или библиотеки используют рефлексию для загрузки классов, вам нужно будет пройти полный тест покрытия вашего приложения и зарегистрировать все загруженные классы, которые вы укажете ProGuard.

Ответ 6

Нет таких гарантий, как упомянули другие плакаты. Но ваш вопрос и ваше беспокойство не следует друг другу. Чтобы вы покинули library.jar, вам не нужны такие гарантии.

Существует несколько фреймворков, которые обнаруживают наличие или отсутствие других фреймворков во время выполнения. Пример: Commons-logging обнаруживает множество других фреймворков. Spring веб-поток обнаруживает, какова структура сценариев (например, OGNL) во время выполнения. Эти структуры, очевидно, скомпилированы с использованием всех зависимых фреймворков, но они не должны существовать во время выполнения.

Следовательно, вполне приемлемо оставлять файл library.jar во время выполнения.

Ответ 7

Да.

Подумайте о следующем. Если вы добавите следующий код в этот класс library.jar:

 public ShutDown {static { System.exit(-1); }}

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

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