Как заставить класс инициализироваться?

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

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() заставить инициализацию.

Однако делать это вообще - запах кода. Попробуйте заменить статический код стандартным конструктором в одноэлементном объекте.

Если вам нужно статически инициализировать что-то в классе, это означает, что должны быть классы клиента, зависящие от этого.

Если есть один клиент, или давайте назовем его естественным домом для блока инициализации, я думаю, что было бы наиболее чистым инициализировать его там.

Для случая с множеством равных клиентов может быть хорошей идеей проверить из этих классов, что статическая инициализация в другом классе прошла успешно. Затем связывание документируется, и вы уверены, что класс всегда инициализируется до того, как это понадобится первому клиенту.

Другие вопросы по тегам