Как заставить класс инициализироваться?
Какой самый лучший и чистый способ сделать это? В частности, мне нужен некоторый код в блоке статического инициализатора для запуска в этом классе, но я бы хотел сделать его максимально чистым.
6 ответов
Загрузка!= Инициализация.
Вы хотите, чтобы ваш класс был инициализирован (это, между прочим, когда выполняются статические блоки).
Выдержка из спецификации языка Java гласит:
Класс T или интерфейсный тип T будут инициализированы непосредственно перед первым появлением> любого из следующих:
- T является классом, и экземпляр T создан.
- T является классом, и вызывается статический метод, объявленный T.
- Статическое поле, объявленное T, присваивается.
- Используется статическое поле, объявленное T, и поле не является константной переменной (§4.12.4).
- T является классом верхнего уровня, и выполняется оператор assert (§14.10), лексически вложенный в T.
Вызов определенных отражающих методов в классе Class и в пакете java.lang.reflect также вызывает инициализацию класса или интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах.
Доу, anovstrup, уже сказал: просто создайте пустую статическую функцию с именем init
, Обязательно документируйте это хорошо... Я лично не вижу ни одного варианта использования этого в контексте правильно сформированного кода.
Вы можете использовать следующий код для принудительной инициализации класса:
//... Foo.class ... //OLD CODE
... forceInit(Foo.class) ... //NEW CODE
/**
* Forces the initialization of the class pertaining to
* the specified <tt>Class</tt> object.
* This method does nothing if the class is already
* initialized prior to invocation.
*
* @param klass the class for which to force initialization
* @return <tt>klass</tt>
*/
public static <T> Class<T> forceInit(Class<T> klass) {
try {
Class.forName(klass.getName(), true, klass.getClassLoader());
} catch (ClassNotFoundException e) {
throw new AssertionError(e); // Can't happen
}
return klass;
}
try
{
Class.forName(class name as string)
}
catch(ClassNotFoundException e)
{
whatever
}
Это должно сделать это.
@Longpoke
Может быть, я что-то неправильно понимаю. Можете ли вы создать пример, где класс загружается, но статический инициализатор не выполняется? Вот пример, который ничего не делает, кроме распечатки загруженного файла:
package test;
public class TestStatic
{
public static void main(String[] args)
{
try
{
Class.forName("test.Static");
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
Загружается следующий класс Static:
package test;
public class Static
{
static
{
System.out.println("Static Initializer ran...");
}
}
Если статические инициализаторы не запускаются до тех пор, пока не будут выполнены перечисленные вами условия, то почему выполняется этот println, когда я запускаю тест? Вот с каким из перечисленных вами условий я встречаюсь?
Невидимые зависимости между классами не очень хорошая идея. Я предлагаю переместить код в блоке статического инициализатора в статический метод и вызвать его непосредственно в зависимом классе. Блок статического инициализатора может быть переписан для вызова вновь созданного статического метода.
Одним из решений было бы вызвать статический метод:
public class A {
static { DebugUtils.FLAG_TEST_USER = true; }
static void init() {}
}
Затем вызвать A.init()
заставить инициализацию.
Однако делать это вообще - запах кода. Попробуйте заменить статический код стандартным конструктором в одноэлементном объекте.
Если вам нужно статически инициализировать что-то в классе, это означает, что должны быть классы клиента, зависящие от этого.
Если есть один клиент, или давайте назовем его естественным домом для блока инициализации, я думаю, что было бы наиболее чистым инициализировать его там.
Для случая с множеством равных клиентов может быть хорошей идеей проверить из этих классов, что статическая инициализация в другом классе прошла успешно. Затем связывание документируется, и вы уверены, что класс всегда инициализируется до того, как это понадобится первому клиенту.