Есть ли способ, чтобы статический блок выполнялся несколько раз? если так то как? - PullRequest
6 голосов
/ 20 мая 2010

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

Сомнение / Вопрос 1) Есть ли время, когда JVM перезагружает класс?

Мое понимание В загрузке классов JVM загружает байт-код файла Java, поэтому он не может хранить все тысячи байт-кодов классов в памяти, поэтому он может отбрасывать редко используемый код и перезагружать его снова, когда это необходимо, и во время перезагрузки JVM не инициализирует статические переменные и блоки снова (возможно, используется какой-то механизм отслеживания)

Сомнение / вопрос
2) Если моё понимание неверно, поправьте меня

Ответы [ 6 ]

6 голосов
/ 20 мая 2010

Насколько мне известно, JVM никогда не перезагрузит класс как таковой; как только класс загружен, он остается загруженным навсегда. По этой причине определения классов хранятся в пуле памяти «PermGen».

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

3 голосов
/ 20 мая 2010

Классы могут быть выгружены, если ClassLoader загрузка их становится недоступной: https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.7

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

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

2 голосов
/ 20 мая 2010

Статический блок выполняется ОДИН И ТОЛЬКО ОДИН РАЗ на загрузчик классов, когда класс загружается. Последовательность выполнения статического блока в соответствии с его возникновением, см. Пример кода ниже и его вывод. Статический код находится на уровне класса, а не на уровне экземпляра для каждого ClassLoader, создающего экземпляр этого класса. Примечание: для краткости я не вызывал метод и его вывод здесь.

открытый класс StaticTest {

 // 1st Static block invoked first.
static{
    System.out.println("hello...1");
}

// 2nd Static block, invoked after 1st static block above.
static{
    System.out.println("hello...2");
}


public static void Staticmeth() {
     System.out.println("hello...3");
}

public static void main(String ag[]){

}

}

вывод программы: -

привет ... 1

привет ... 2

1 голос
/ 20 мая 2010

Если вы явно используете новый ClassLoader для повторной загрузки класса, статический блок для этого класса будет выполнен снова.

0 голосов
/ 21 мая 2010

Анджей Дойл ответил на ваш конкретный вопрос. Тем не менее:

Мой блок статического понимания выполнено во время загрузки класса

Для ясности, загрузка и инициализация - это разные фазы; класс может быть загружен без инициализации. Спецификация виртуальной машины Java определяет три условия, которые приведут к инициализации класса: создается экземпляр, вызывается статический метод или используется или назначается непостоянное статическое поле.

0 голосов
/ 20 мая 2010

Спецификация языка Java подробно описывает механизм загрузки, выгрузки и перезагрузки классов.

JLS 12.2 Загрузка классов и интерфейсов

Загрузка относится к процессу поиска двоичной формы типа class или interface с конкретным именем, возможно, путем его вычисления на лету, но более обычно путем извлечения двоичного представления, предварительно вычисленного из исходного кода компилятором, и создания из этой двоичной формы объекта Class для представления класса или интерфейса.

Точная семантика загрузки дана в главе 5 Спецификации виртуальной машины Java (всякий раз, когда мы ссылаемся на спецификацию виртуальной машины Java в этой книге, мы имеем в виду второе издание с поправками, внесенными в JSR 924). Здесь мы представляем обзор процесса с точки зрения языка программирования Java.

Бинарный формат класса или интерфейса обычно представляет собой формат файла класса, описанный в приведенной выше спецификации виртуальной машины Java, но возможны и другие форматы при условии, что они соответствуют требованиям, указанным в §13.1. Метод defineClass из class ClassLoader может использоваться для создания Class объектов из двоичных представлений в формате файла класса.

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

12.7 Выгрузка классов и интерфейсов

Реализация языка программирования Java может выгружать классы. Класс или интерфейс могут быть выгружены, если и только если их определяющий загрузчик класса может быть восстановлен сборщиком мусора, как обсуждалось в §12.6. Классы и интерфейсы, загруженные загрузчиком начальной загрузки, не могут быть выгружены.

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

Однако, если класс или интерфейс C был выгружен, а его определяющий загрузчик потенциально доступен, то C может быть перезагружен. Никогда нельзя было гарантировать, что этого не произойдет.

На самом деле, это пошло для решения ваших конкретных проблем:

Перезагрузка может быть не прозрачной, если, например, класс имеет:

  • Статические переменные (состояние которых будет потеряно).
  • Статические инициализаторы (которые могут иметь побочные эффекты).
  • Собственные методы (которые могут сохранять статическое состояние).

Кроме того, значение хеш-функции объекта Class зависит от его идентичности. Поэтому, как правило, невозможно полностью перезагрузить класс или интерфейс.

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

Необходимо также спорить, почему безопасно выгружать класс C, если его определяющий загрузчик классов может быть восстановлен. Если определяющий загрузчик может быть восстановлен, то никогда не может быть никаких живых ссылок на него (это включает ссылки, которые не являются живыми, но могут быть воскрешены финализаторами). Это, в свою очередь, может быть правдой только в том случае, если никогда не может быть никаких живых ссылок ни на один из классов, определенных этим загрузчиком, включая C, либо из их экземпляров, либо из кода.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...