为什么.class不调用Class中的静态块?


69

这是我的代码:

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

但是,当我运行测试栏时,我看到的只是:

StupidClass

引用页面。

Java虚拟机会在加载类时以及通过调用类加载器中的defineClass方法自动构造类对象。

所以我的理解是,在测试栏中,加载了Stupid类,否则我会看到一个空值吗?因此创建Class对象是因为类本身已加载。

现在引用页面

当JVM(具体来说是类加载器)加载StaticClass(在代码中首次引用它)时,将运行静态初始化块。

因此,我期望看到“愚蠢的类已加载!” 测试栏中的文本也可以,但我不是。

也引用了《用Java思考》

Candy,Gum和Cookie的每个类都有一个静态子句,该子句是在首次加载该类时执行的。

似乎不太准确。

我想念什么?


您应该提及是否将两个测试作为一个或单独的进程运行。
阮阮

@DuongNguyen我做了吗?“还有我分别进行的测试。”
Koray Tugay

我的错。有趣的问题。我的猜测是在这种情况下该类尚未真正加载。
阮阮

@DuongNguyen-否。已加载。它尚未初始化
TheLostMind

Answers:


61

当JVM(具体来说是类加载器)加载StaticClass(在代码中首次引用它)时,将运行静态初始化块。

上面的引用是完全错误的,但这只是一种非常普遍的误解的例子。

  1. 加载类时,不会初始化类,但会在首次引用静态类成员时对其进行初始化。这完全由规范支配

  2. 首次引用该类时不会发生类加载,而是在依赖于实现的点上进行。

  3. 必须加载类的最后时刻是引用该类时,这引用类member不同

Class.forName默认情况下会初始化该类,但是您可以选择调用一个带有aboolean initialize和supplying的重载false。您无需初始化即可加载该类。


请注意,它必须是« static»成员才能触发类初始化。访问实例成员意味着要么是先前的实例化(因此该类已被初始化),要么是null不会触发clazz初始化的访问。这也意味着您可以在interface不触发接口初始化的情况下调用方法。
Holger

我以为“类成员”隐含静态成员,但是您可能是对的。
Marko Topolnik

24

类加载和初始化是两件事。可以加载一个类,但只有在确实需要它时才可以初始化。静态初始化程序仅在初始化类时运行<>未加载,“初始化”

在第一种情况下,您在使用时要加载和初始化类class.forName(),这就是为什么要运行静态初始化程序,因此将其"Stupid class loaded!"视为output的原因。在第二种情况下,您只是分配了该类的引用,该类已加载(使用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/]
...

^-这表明该类已加载但尚未初始化。


而且我相信docs.oracle.com/javase/specs/jls/se7/html/…中对此进行了介绍,
nos

@nos-应该覆盖
TheLostMind
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.