【发布时间】:2012-01-22 22:45:00
【问题描述】:
据说java中的静态块只在加载该类时运行一次。但它实际上是什么意思? JVM(Java虚拟机)在什么时候加载一个类?
是在调用该类中的主要方法时吗?而且是不是同一个类的所有超类在main方法开始执行的时候也被加载了?
考虑 A 扩展 B 和 B 扩展 C。它们都有静态块。如果A有main方法,那么静态块的执行顺序是什么?
【问题讨论】:
标签: java classloader static-block
据说java中的静态块只在加载该类时运行一次。但它实际上是什么意思? JVM(Java虚拟机)在什么时候加载一个类?
是在调用该类中的主要方法时吗?而且是不是同一个类的所有超类在main方法开始执行的时候也被加载了?
考虑 A 扩展 B 和 B 扩展 C。它们都有静态块。如果A有main方法,那么静态块的执行顺序是什么?
【问题讨论】:
标签: java classloader static-block
这在 JLS 的 Execution 部分中进行了描述。即:
类的初始化包括执行其静态初始化程序和类中声明的静态字段的初始化程序。接口的初始化包括执行接口中声明的字段的初始化程序。
在初始化一个类之前,必须初始化它的直接超类,但该类实现的接口不需要初始化。同样,接口的超接口也不需要在接口初始化之前进行初始化。
因此,在您的示例中,“最顶层”类 (C) 的静态块首先运行,然后是 B 的静态块,然后是派生最多的。
有关加载类的所有步骤的详细说明,请参阅该文档。
(类在第一次被主动使用时被加载。)
【讨论】:
我认为下面的例子会解决你所有的问题:
在一个类被初始化之前,它的超类被初始化,如果它们之前没有被初始化的话。
因此,测试程序:
class Super {
static { System.out.print("Super "); }
}
class One {
static { System.out.print("One "); }
}
class Two extends Super {
static { System.out.print("Two "); }
}
class Test {
public static void main(String[] args) {
One o = null;
Two t = new Two();
System.out.println((Object)o == (Object)t);
}
}
打印:
Super Two false
类 One 永远不会被初始化,因为它没有被主动使用,因此永远不会被链接到。类 Two 仅在其超类 Super 被初始化后才被初始化。
更多详情请访问link
编辑详细信息:删除了令人困惑的行。
【讨论】:
来自Java Language Specification:
类的初始化包括执行其静态初始化程序和类中声明的静态字段(类变量)的初始化程序。接口的初始化包括执行在那里声明的字段(常量)的初始化程序。
在一个类被初始化之前,它的超类必须被初始化,但是类实现的接口没有被初始化。同样,接口的超接口在接口初始化之前也不会被初始化。
Java Virtual Machine Specification 中更详细地描述了该过程。
【讨论】: