Почему класс не вызывает статический блок в классе?

Это код, который у меня есть:

public class StupidClass {
    static {
        System.out.println("Stupid class loaded!");
    }
}

И тесты, которые у меня есть, которые я запускаю отдельно.

import org.junit.Test;

public class StupidTest {
    @Test
    public void foo() throws ClassNotFoundException {
        final Class<?> stupidClass = Class.forName("StupidClass");
        System.out.println(stupidClass.getSimpleName());
    }

    @Test
    public void bar() throws ClassNotFoundException {
        final Class<StupidClass> stupidClassClass = StupidClass.class;
        System.out.println(stupidClassClass.getSimpleName());
    }
}

Когда я запустил тест foo, я увижу:

Stupid class loaded!
StupidClass

Но когда я запускаю тест bar, я вижу следующее:

StupidClass

Цитата из эта страница.

Объекты класса автоматически создаются виртуальной виртуальной машиной Java Virtual Загружается машина как классы и вызовы метода defineClass в загрузчике классов.

Итак, я понимаю, что в тестовой панели загружен класс Stupid, иначе я бы увидел нуль, я думаю? Таким образом, объект класса создается, потому что сам класс загружается.

И теперь, ссылаясь на эту страницу

Статические блоки инициализации запускаются, когда JVM (загрузчик классов - быть конкретным) загружает StaticClass (что происходит в первый раз ссылка на код).

Итак, я ожидаю увидеть, что "Stupid class загружен!" текст в тестовой панели, но я не знаю.

Также цитируется Мышление в Java

Каждый из классов Candy, Gum и Cookie имеет статическое предложение, которое выполняется, когда класс загружается в первый раз.

который не очень точен, кажется.

Что мне не хватает?

Ответ 1

Статические блоки инициализации запускаются, когда JVM (загрузчик класса - конкретный) загружает StaticClass (что происходит при первом обращении к нему в коде).

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

  • Класс не инициализируется при его загрузке, но когда статический член класса сначала ссылается. Это точно определяется спецификацией.

  • Загрузка класса не происходит, когда класс сначала ссылается, но в точке, зависящей от реализации.

  • Последний момент, когда класс должен быть загружен, это когда класс ссылается, что не совпадает с ссылкой на член класса.

Class.forName инициализирует класс по умолчанию, но у вас есть выбор вызова перегрузки, которая принимает boolean initialize и предоставляет false. Вы получите класс, загруженный без инициализации.

Ответ 2

Загрузка и инициализация классов - это две разные вещи. Класс может быть загружен, но не инициализирован, пока он действительно не понадобится. Статические инициализаторы запускаются только тогда, когда инициализируется класс < > NOT загружен, "инициализирован"

В первом случае вы загружаете и инициализируете класс при использовании class.forName(), поэтому запускаются статические инициализаторы и, следовательно, вы видите "Stupid class loaded!" как вывод. Во втором случае вы просто назначаете ссылку класса, класс загружается (используйте java -verbose: class, чтобы посмотреть, какие классы загружены), но вы на самом деле не инициализируете его (или точнее, не делать ничего, что заставляет инициализаторы запускаться). Таким образом, вы не видите вывод как Stupid class loaded!. Попробуйте сделать что-то вроде вызова newInstance() в классе, оно должно принудительно инициализировать класс, и вы должны увидеть Stupid class loaded!

Мой код:

public class CheckPalindrome {

    public static void main(String[] args) {
        Class<Test> t = Test.class;
    }

}
// class being loaded
class Test {
    static {
        System.out.println("aaa");
    }
}

Загруженные классы

...
[Loaded Test from file:/Workspaces/SampleTest/Java8/bin/]
...

^ - Это показывает, что класс загружен, но не инициализирован.