Как отключить ленивую загрузку / инициализацию класса в JVM от Sun? - PullRequest
12 голосов
/ 14 декабря 2011

По умолчанию JVM от Sun лениво загружает классы и лениво инициализирует (то есть вызывает их <clinit> методы) их.Рассмотрим следующий класс ClinitBomb, который выбрасывает Exception во время блока static{}.

public class ClinitBomb {
    static {
        explode();
    }   
    private static void explode() {
        throw new RuntimeException("boom!");
    }       
}

Теперь рассмотрим, как запустить бомбу:

public class Main {
    public static void main(String[] args) {
        System.out.println("A");
        try {
            Class.forName("ClinitBomb");
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
        System.out.println("B");
        ClinitBomb o2 = new ClinitBomb();
        System.out.println("C");
    }
}

МыВы уверены, что взрыв произойдет до точки B, так как документация forName так говорит;вопрос в том, произойдет ли это до точки A (когда загружено Main). В JVM Sun, даже если main() содержит статическую ссылку на ClinitBomb, это происходит после A.

Я хочуспособ сказать JVM загрузить и инициализировать ClinitBomb, как только он инициализирует Main (таким образом, бомба взрывается до пункта A.) В общем, я хочу сказать "всякий раз, когда загружается /инициализировать класс X, также сделайте это для любых классов Y, на которые он ссылается. "

Есть ли способ сделать это?

Ответы [ 2 ]

9 голосов
/ 14 декабря 2011

Нет способа сделать это.JLS говорит, в §12.4.1, когда происходит инициализация (выделено мое):

Инициализация класса состоит из выполнения его статических инициализаторов и инициализаторов для статических полей, объявленных вкласс.[...]

Класс T или интерфейсный тип T будут инициализированы непосредственно перед первым возникновением любого из следующих действий: :

  • T являетсякласс и создается экземпляр T.
  • T является классом, и вызывается статический метод, объявленный T.
  • Назначается статическое поле, объявленное T.
  • Используется статическое поле, объявленное T, и поле не является константной переменной (§4.12.4).
  • T является классом верхнего уровня, и утверждение assert (§14.10), лексически вложенное в T, являетсяказнены.

Вызов определенных отражающих методов в классе Class и в пакете java.lang.reflect также вызывает инициализацию класса или интерфейса. Класс или интерфейс не будут инициализированы ни при каких других обстоятельствах .

Реализация Java, которая инициализировала классы, как только они были загружены, будет нарушать JLS.

Хотя то, что вы могли бы сделать, это использовать инструментарий JVM API для записи ClassFileTransformer , который добавляет статический блок к каждому классу, который явно инициализирует свои ссылочные классы (через Class.forName,наверное).Как только один класс инициализируется, все доступные ему классы будут инициализированы.Это может дать вам результат, который вы после.Хотя работы довольно много!

1 голос
/ 14 декабря 2011
Class.forName("...", true /*initialize*/, getClassLoader());

Вы были на полпути.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...