Как проверить, инициализирован ли класс?

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

Я просмотрел ClassLoader, но не нашел ничего полезного. Любые идеи?


person mik01aj    schedule 09.09.2010    source источник
comment
вы имеете в виду, инициализирован ли класс. есть огромная разница.   -  person irreputable    schedule 09.09.2010
comment
Спасибо что подметил это. Я изменил название.   -  person mik01aj    schedule 09.09.2010
comment
Какая библиотека? Возможно, есть побочный эффект, который вы могли бы проверить (например, драйверы JDBC регистрируются в DriverManager).   -  person Thomas Mueller    schedule 09.09.2010
comment
Это библиотека, используемая внутри компании, в которой я работаю. Спасибо за подсказку, может что найду.   -  person mik01aj    schedule 09.09.2010


Ответы (7)


Вы можете использовать метод ClassLoader.findLoadedClass(). Если он возвращает null, то класс не загружен. Таким образом, вы не загружаете класс, если он еще не загружен.


ВНИМАНИЕ: этот код здесь не работает, в системе ClassLoader findLoadedClass() защищен, вам нужно переопределить его своим собственным ClassLoader.

Перейдите по ссылке ниже В той же теме, чтобы проверить, загружен ли класс с помощью системного ClassLoader

if(ClassLoader.getSystemClassLoader().findLoadedClass("java.lang.String") != null){
    System.out.println("Yepee, String is loaded !");
}

Очень хороший момент от @irreputable:

«загружено» не означает «инициализировано». инициализация происходит только в точные моменты, определенные JLS3 $ 12.4.1

И цитирую:

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

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

Вызов определенных рефлексивных методов в классе Class и в пакете java.lang.reflect также вызывает инициализацию класса или интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах.


Ресурсы:

По той же теме:

person Colin Hebert    schedule 09.09.2010
comment
Не приведет ли это к загрузке String при вызове метода, так как он должен оценить литерал String "java.lang.String"? - person Nate W.; 09.09.2010
comment
Ну, на самом деле код вообще не работает, мы не можем вызвать findLoadedClass() в загрузчике классов по умолчанию. Итак, рассмотрим это как простой пример. - person Colin Hebert; 09.09.2010
comment
Конечно, надуманный простой пример, но, тем не менее, не будет ли ваш оператор if всегда оцениваться как true? - person Nate W.; 09.09.2010
comment
Что ж, если бы это сработало, то всегда было бы true (или взорвалось бы в ClassNotFoundException, поскольку буквальная строка была бы непонятна: P). - person Colin Hebert; 09.09.2010
comment
загружен не значит инициализирован. инициализация происходит только в точные моменты, определенные JLS3 $ 12.4.1 - person irreputable; 09.09.2010

Почему бы вам просто не сослаться на класс (создав ссылку, создав экземпляр или обратившись к статическому члену)? Это запустит инициализатор типа, если он еще не сработал, а если сработал, то все еще готово.

person Andrew Hare    schedule 09.09.2010
comment
Потому что эта библиотека читает параметры с System.getProperty и мне нужно знать, могу ли я их еще изменить или нет. - person mik01aj; 09.09.2010

Вы можете попробовать что-то вроде этого:

Класс c = новый ClassLoader () { Класс c = findLoadedClass (имя класса); }.с;

person Eugene Kuleshov    schedule 09.09.2010

Вы можете заставить JVM распечатывать классы по мере их загрузки, используя флаг -verbose. Это может вам помочь.

java -verbose Dummy|head
[Opened C:\Program Files\Java\jre6\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\Java\jre6\lib\rt.jar]
[Loaded java.io.Serializable from C:\Program Files\Java\jre6\lib\rt.jar]
[Loaded java.lang.Comparable from C:\Program Files\Java\jre6\lib\rt.jar]
[Loaded java.lang.CharSequence from C:\Program Files\Java\jre6\lib\rt.jar]
[Loaded java.lang.String from C:\Program Files\Java\jre6\lib\rt.jar]

(кстати, только что попробовал это в программе Hello World, и она загрузила 309 классов! вау)

person dogbane    schedule 09.09.2010

Я знаю, что уже очень поздно, но я думаю, что этот ответ может быть полезен. Если вы не слишком боитесь (и вам разрешено) использовать класс sun.misc.Unsafe, есть метод, который точно делает это: метод

sun.misc.Unsafe.shouldBeInitialized(Class)

возвращает true тогда и только тогда, когда Class, указанный в качестве параметра, (загружен, но) не инициализирован.

person Pietro Braione    schedule 24.01.2018

Class.forName("com.abc.Xyz", true, this.getClass().getClassLoader())

Он будет блокироваться до тех пор, пока класс не будет инициализирован (сам по себе или какой-либо другой поток)

person irreputable    schedule 09.09.2010

Если еще не слишком поздно.. Это тоже должно работать нормально

 Class.forName().newInstance();

newInstance() создает новый экземпляр класса, представленного этим объектом Class. Класс создается как бы новым выражением с пустым списком аргументов. Класс инициализируется, если он еще не был инициализирован.

person Zuko    schedule 31.08.2016
comment
Примечание: это будет только работать, если доступен конструктор без параметров. Это не всегда так (если вы определяете один или несколько конструкторов с параметрами, но также явно не определяете конструктор без параметров). - person Per Lundberg; 13.08.2019