Что приведет к инициализации класса Java?

1

Я использую метод класса Wrapper, чтобы позволить мне обрабатывать класс, существующий или нет. При использовании этого метода важно знать, что приведет к инициализации моего класса Proxy. В частности, что, если я:

  1. Объявить экземпляр Proxy не устанавливая его ни на что

    public class myClass {... Proxy myInst; }

  2. Объявление экземпляра Proxy локально внутри никогда не выполняемого оператора if

    public void myMeth {if (ProxyIsAvailableWhichItIsNot) {Proxy myInst; ... } }...}}

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

  • 0
    Кажется, я задал похожий вопрос, когда работал над Java ME
Теги:
classloader

3 ответа

2
Лучший ответ

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

Напротив, существуют точные правила для того, когда инициализируется класс (запускаются статические инициализаторы), а именно, когда создается первый объект, созданный классом, или вызываемый статический метод или нестационарное статическое поле.

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

Техника "класса обертки", описанная в вашей ссылке, не гарантируется работой Java (см. Раздел 12.1.2 Спецификации языка Java, 3-е издание), но вполне возможно, что Android/Dalvik дает более серьезные гарантии.

  • 1
    Благодарю. Я имел ввиду инициализацию, а не загрузку. То есть вы говорите, что ни одна из этих ситуаций не должна вызывать инициализацию класса?
  • 0
    Да, но что хорошего в том, что если даже загрузка вашего класса заставляет JVM NoClassDefFoundError потому что базовый класс не может быть найден (поскольку JVM разрешено, но не обязательно, делать в этот момент)?
Показать ещё 2 комментария
2

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

  1. Создайте логическое значение, например, IsMyProxyAvailable
  2. Вызовите свой статический метод checkAvailable() в своем прокси-классе
  3. Задайте значение true, когда метод будет успешным, false, если вы его не вызываете.

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

  • 0
    У меня действительно есть логическое значение, просто мне нужно некоторое время держать прокси, поэтому я не могу просто сохранить его локально. Я просто переключился на использование объекта и приведение его локально
  • 0
    Я не утверждаю, что Object - плохой путь, но я обнаружил, что как можно более строгое типизирование обычно приводит к большему количеству ошибок во время выполнения, которые выявляются компилятором, а не позже в отладчике.
Показать ещё 3 комментария
0

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

Что запускает класс для загрузки? Загружается другой класс, который зависит от него. Когда компилятор Java компилирует класс, он записывает в файл класса все классные имена, от которых он зависит. Классы загружаются как можно позже, так что обычно это означает, что вы создаете их в обычных условиях. Однако наличие статических элементов будет принудительно загружать те, которые будут загружены до загрузки этого класса. Члены экземпляра будут загружены, когда этот класс также будет создан. Если вы хотите получить много хороших деталей этого процесса, прочитайте следующее:

http://www.ibm.com/developerworks/java/library/j-dyn0429/

К счастью, Dalvik VM работает замечательно, как JVM, потому что Java подробно описывает этот процесс.

Если вы используете метод Wrapper в статическом инициализаторе, если класс Class.forName() преуспевает, не имеет значения, когда вы определяете Proxy (вариант 1 или 2), потому что он уже будет загружен. В противном случае родительский класс Wrapper не загружается. Так что просто сделайте вариант 1, поскольку он проще.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню