假设一个项目包含几个类,每个类都有一个静态初始化块。这些块以什么顺序运行?我知道在一个类中,这些块按照它们在代码中出现的顺序运行。我已经读过它在各个类中都是一样的,但是我写的一些示例代码不同意这一点。我用了这段代码:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
得到了这个输出:
START
静态 - 祖父母 静态 - 父母 静电 - 儿童
实例 - 祖父母 建设者 - 祖父母
实例 - 父母 构造函数 - 父母
实例 - 孩子
建设者 - 孩子
END
显而易见的答案是,父母的障碍在他们的孩子面前运行,但这可能只是巧合而且如果两个班级不在同一层级中则无济于事。
编辑:
我通过将此示例代码附加到LoadTest.java来修改我的示例代码:
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
正如类名所暗示的那样,我从未在任何地方引用过新类。新程序产生的输出与旧程序相同。
答案 0 :(得分:90)
参见JLS version 8的第12.4节和第12.5节,它们详细介绍了所有这些(静态12.5和实例变量12.5)。
对于静态初始化(第12.4节):
类或接口类型T将在第一次出现以下任何一个之前立即初始化:
(以及几个狡猾的词条)
答案 1 :(得分:60)
首次访问类时,会运行类的静态初始化程序,以创建实例或访问静态方法或字段。
因此,对于多个类,这完全取决于运行导致这些类加载的代码。
答案 2 :(得分:31)
Keith和Chris的答案都很棒,我只是为我的具体问题添加更多细节。
静态初始化块按其初始化类的顺序运行。那么,这是什么顺序?根据JLS 12.4.1:
类或接口类型T将在第一次出现以下任何一个之前立即初始化:
- T是一个类,创建了一个T实例。
- T是一个类,调用T声明的静态方法。
- 分配由T声明的静态字段。
- 使用由T声明的静态字段,该字段不是常量变量(§4.12.4)。
- T是顶级类,并且执行词法嵌套在T中的断言语句(第14.10节)。
在类Class和包java.lang.reflect中调用某些反射方法也会导致类或接口初始化。在任何其他情况下,不会初始化类或接口。
为了说明,这里是对示例中发生的事情的演练:
答案 3 :(得分:1)
类的初始化包括执行静态初始化器和类中声明的静态字段(类变量)的初始化器。
接口的初始化包括执行接口中声明的字段(常量)的初始化器。
在初始化类之前,必须初始化其直接超类,但不会初始化类实现的接口。同样,在初始化接口之前,不会初始化接口的超接口。
答案 4 :(得分:0)
您可以在同一个类中拥有多个静态和实例初始值设定项,因此
每个都像一个块一样被执行。
答案 5 :(得分:0)
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
请检查java文档。
然后清楚地提到无论静态块如何存在,它们将按照它们出现的顺序作为单个块执行
所以,
我的理解是java正在将您的代码视为
static{
i=1;
i=2;
}
static int i;
这就是你得到输出2
的原因希望这有用
答案 6 :(得分:0)
有一种情况是不会调用静态块。
class Super {
public static int i=10;
}
class Sub extends Super {
static {
system.out.println("Static block called");
}
}
class Test {
public static void main (String [] args) {
system.out.println(Sub.i);
}
}
以上代码输出10
答案 7 :(得分:0)
class A {
public A() {
// 2
}
}
class B extends A{
static char x = 'x'; // 0
char y = 'y'; // 3
public B() {
// 4
}
public static void main(String[] args) {
new B(); // 1
}
}
注释中的数字表示评估顺序,越小,越早。
如示例所示,