Каков наилучший и самый чистый способ сделать это? В частности, мне нужен код в статическом блоке инициализатора для запуска в этом классе, но я хотел бы сделать это как можно более чистым.
Как заставить класс быть инициализированным?
Ответ 1
Загрузка!= Инициализация.
Вы хотите, чтобы ваш класс был инициализирован (это, в частности, статические блоки).
Отрывок из Спецификация языка Java гласит:
Тип класса или интерфейса T будет инициализирован непосредственно перед первым вхождением > любого из следующих:
- T - это класс и создается экземпляр T.
- T - класс, и статический метод, объявленный T, вызывается.
- Назначено статическое поле, объявленное T.
- Используется статическое поле, объявленное T, и поле не является постоянной переменной (§4.12.4).
- T - класс верхнего уровня, и выполняется инструкция assert (§14.10), лексически вложенная в T.
Вызов некоторых отражающих методов в классе Class и в пакете java.lang.reflect также вызывает инициализацию класса или интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах.
Doh, anovstrup, уже сказал это: просто создайте пустую статическую функцию под названием init
. Обязательно запишите это хорошо... Я лично не вижу никакого примера для этого в контексте хорошо сформированного кода.
Ответ 2
Вы можете использовать следующий код, чтобы принудительно инициализировать класс:
//... 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;
}
Ответ 3
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();
}
}
}
При загрузке следующего статического класса:
package test;
public class Static
{
static
{
System.out.println("Static Initializer ran...");
}
}
Если статические инициализаторы не выполняются до тех пор, пока не будут выполнены указанные вами условия, то почему этот println выполняется, когда я запускаю свой тест? То есть, какие из перечисленных вами условий я встречаю?
Ответ 4
Невидимые зависимости между классами не являются хорошей идеей. Я предлагаю переместить код в статическом блоке инициализатора в статический метод и вызвать его непосредственно в зависимом классе. Статический блок инициализатора можно переписать для вызова вновь созданного статического метода.
Ответ 5
Одним из решений было бы вызвать статический метод:
public class A {
static { DebugUtils.FLAG_TEST_USER = true; }
static void init() {}
}
Затем вызовите A.init()
для принудительной инициализации.
Однако делать это вообще - это запах кода. Рассмотрите возможность замены статического кода на стандартный конструктор в одном объекте.
Ответ 6
Если вам нужно статически инициализировать что-то в классе, это означает, что на нем должны быть зависимы от клиентских классов.
Если есть один клиент, или позвольте ему называть его естественным домом для блока инициализации, я думаю, что было бы самым чистым его инициализировать.
Для случая с множеством одинаковых клиентов может быть хорошей идеей проверить из этих классов, что статическая инициализация в другом классе была успешной. Затем связь документируется, и вы уверены, что класс всегда инициализируется до того, как ему будет нужен первый клиент.