这是我的代码:
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
从this页面引用..
类对象由Java Virtual自动构造 通过调用defineClass方法加载机器作为类 在类加载器中。
所以我的理解是,在测试栏中,Stupid类被加载,否则我会看到null我猜?因此创建了Class对象,因为类本身已被加载..
现在引用this页面
静态初始化块在JVM(类加载器 - 到 具体)加载StaticClass(第一次出现时) 在代码中引用。)
所以我期待看到“Stupid类加载!”测试栏中的文字,但我不是。
同时引用Thinking in Java
每个类Candy,Gum和Cookie都有一个静态子句 在第一次加载类时执行。
看起来不太准确..
我错过了什么?
答案 0 :(得分:59)
当JVM(类加载器 - 要特定)加载StaticClass(第一次在代码中引用时出现)时,运行静态初始化块。
以上引用是完全错误的,但它只是一个非常普遍的误解的一个例子。
类在加载时未初始化,但首次引用静态类成员时。这完全由specification。
首次引用类时,类
必须加载类的最后一刻是引用类时,与引用类成员不一样。
Class.forName
默认情况下初始化该类,但您可以选择调用需要boolean initialize
并提供false
的重载。你将在没有初始化的情况下加载类。
答案 1 :(得分:22)
类加载和初始化是两回事。可以加载一个类,但在真正需要之前不进行初始化。静态初始值设定项仅在初始化类时运行&lt;&gt;未加载,“已初始化”
在第一种情况下,当您使用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/]
...
^ - 这表明该类已加载但未初始化。