Как проверить, инициализирован ли класс?
вы, вероятно, спросите, почему я хочу это сделать-это потому, что я использую класс (из внешней библиотеки), который делает вещи в своем статическом инициализаторе, и мне нужно знать, было ли это сделано или нет.
Я посмотрел на ClassLoader
, но не нашел ничего полезного. Есть идеи?
7 ответов
можно использовать ClassLoader.findLoadedClass()
метод. Если он возвращает null, то класс не загружается. Таким образом, вы не загружаете класс, если он еще не был загружен.
предупреждение: этот код на самом деле не работает здесь, в загрузчике системных классов, findLoadedClass()
защищена, вы должны заменить его своим загрузчиком.
Проверьте ссылку ниже по теме чтобы проверить, загружен ли класс системой 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
также вызывает инициализацию класса или интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах.
ресурсы :
- Javadoc -
ClassLoader.findLoadedClass()
- внутренние компоненты Java Загрузка Класса
- JLS - §12.4.1 при инициализации
по теме :
Почему бы вам просто не ссылаться на класс (путем создания ссылки, создания экземпляра или доступа к статическому члену)? Это запустит инициализатор типа, если он еще не запущен, и если он есть, то вам все еще хорошо идти.
вы можете заставить 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 классов! вау)
вы можете попробовать что-то вроде этого:
Class c = new ClassLoader () { Class c = findLoadedClass (className);}.c;
Я знаю, что уже очень поздно, но я думаю, что этот ответ может быть полезен. Если вы не слишком напуганы (и разрешается) использовать sun.misc.Unsafe
class существует метод, который точно это: метод
sun.misc.Unsafe.shouldBeInitialized(Class)
возвращает true
, если и только если Class
при условии, что параметр (загружен, но) не инициализирован.
Class.forName("com.abc.Xyz", true, this.getClass().getClassLoader())
он будет блокировать, пока класс не будет инициализирован (сам по себе или какой-либо другой поток)
Если это не слишком поздно.. Это должно работать хорошо, а
Class.forName().newInstance();
на newInstance()
создает новый экземпляр класса, представленного этим Class объект. Экземпляр класса создается как бы новым выражением с пустым списком аргументов. Класс инициализируется, если он еще не был инициализирован.