Подтвердить что ты не робот

Как заставить класс быть инициализированным?

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

4b9b3361

Ответ 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

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

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

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