静态变量初始化顺序,Java

静态变量初始化顺序,Java,java,static,Java,Static,可能重复: 当我运行这个代码时,答案是1,我想应该是2。 每个步骤的初始化顺序和k值是多少 公共类测试{ 静态{k=2;} 静态int k=1; 公共静态void main(字符串[]args){ 系统输出println(k); } } 编辑1:作为“k设置为默认值”的后续,那么为什么下一个代码不编译?出现错误“无法在定义字段之前引用它” 公共类测试{ 静态{System.out.println(k);} 静态int k=1; 公共静态void main(字符串[]args){ 系统输出p

可能重复:

当我运行这个代码时,答案是1,我想应该是2。 每个步骤的初始化顺序和k值是多少

公共类测试{
静态{k=2;}
静态int k=1;
公共静态void main(字符串[]args){
系统输出println(k);
}
}
编辑1:作为“k设置为默认值”的后续,那么为什么下一个代码不编译?出现错误“无法在定义字段之前引用它”

公共类测试{
静态{System.out.println(k);}
静态int k=1;
公共静态void main(字符串[]args){
系统输出println(k);
}
}
编辑2:因为一些我不知道的原因,当它的“Test.k”代替了“k”时,它会工作


谢谢你的回答。这将确保:D

它们按照您编写它们的顺序执行。如果代码为:

public class Test {

    static int k = 1;
    static {k = 2;}

    public static void main(String[] args) {
        System.out.println(k);
    }

}
然后输出变为2

初始化的顺序是:

(代码的)值是:k=0(默认值),然后设置为2,然后再设置为1

通过运行以下代码,可以检查它是否实际设置为2:

private static class Test {

    static {
        System.out.println(Test.k);
        k = 2;
        System.out.println(Test.k);
        }
    static int k = 1;

    public static void main(String[] args) {
        System.out.println(k);
    }
}

简短回答

当类的初始化开始时,
k
的初始值为0

然后执行静态块(因为它位于声明中的赋值之前),并将
k
赋值为2

然后执行声明中的初始值设定项,
k
将被指定为1

详细解释

让我们使用,因为您的示例有点简单:

class TestInitOrder {
  static {
    System.out.println(TestInitOrder.stat1);
    System.out.println(TestInitOrder.stat2);
    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.str2);

    str = "something";

    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.str2);
    System.out.println(TestInitOrder.lazy);
    System.out.println(TestInitOrder.second);
  }

  private static final int stat1 = 10;
  static final String str2 = "sdfff";
  static String str = "crap";
  private static int stat2 = 19;
  static final Second second = new Second();
  static final int lazy;

  static {
    lazy = 20;
  }

  static {
    System.out.println(TestInitOrder.str2);
    System.out.println(TestInitOrder.stat2);
    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.lazy);
    System.out.println(TestInitOrder.second);
  }

  public static void main(String args[]) {
  }

}

class Second {
  public Second() {
    System.out.println(TestInitOrder.second);
  }
}
根据,来自:

程序中的每个变量在使用其值之前必须有一个值:

  • 每个类变量、实例变量或数组组件在创建时都会使用默认值进行初始化
(规范中的以下行指定了所有类型的默认值,基本上是0的某种形式,例如
0
0.0d
null
false
,等等。)

因此,在初始化类之前(由于其中一个原因),变量将保存一个初始值

根据(这里只引用了有趣的步骤,重点是我的):

六,。 […]然后,初始化接口的
最终
类变量和字段,其值为编译时常量表达式(§8.3.2.1、§9.3.1、§13.4.9、§15.28)

[……]

九,。 接下来,按照文本顺序执行类的类变量初始值设定项和静态初始值设定项,或者执行接口的字段初始值设定项,就像它们是单个块一样

让我们看一下步骤6,其中有4个
最终的
类变量:
stat1
str2
惰性

由于
10
是常量表达式,因此
“sdfff”
也是常量表达式,并且由于执行顺序的原因,无法观察
str2
stat1
的初始值。为了进行观察,最早可以在步骤9中进行

second
的情况表明,当右侧不是编译时常量表达式时,其初始值是可见的

惰性
的情况不同,因为赋值是在静态块中完成的,因此在步骤9中发生-因此可以观察其初始值。(好吧,编译器会仔细检查
lazy
是否只分配了一次)


在使用编译时常量表达式初始化最终类变量之后,执行静态块和其他初始化程序


从示例中可以看出,静态块和初始化是根据文本顺序进行的-通过使用
str
变量进行演示-首先将其打印为
null
,然后打印为
something
,然后是
crap

,首先,k将被指定为默认值,然后从顶部开始,将运行静态代码,分配2个,然后分配1个。然后调用main函数并打印出k
static int k=1
实际上是
static int k声明,然后
静态{k=1;}
@KennyTM是的,如果我像你粘贴的帖子那样运行它,我就会知道发生了什么。@nhahtdh会给k分配默认值吗?那么为什么这段代码没有混合:公共类Test{static{System.out.println(k);k=2;}static int k;公共静态void main(String[]args){System.out.println(k);}}}@Hoto:(使用
Test.k
打印它)。我没有足够的知识来解释整个情况。From:1)最终字段将根据初始值设定项进行初始化2)静态初始值设定项和静态块将根据文本顺序运行(在运行块之前,静态字段将具有默认值)一个测试程序来演示我的观点:关于这一点,我的问题不是这个意思。我想要初始化的顺序和每个步骤中k的值。好的,我添加了一个更详细的解释。是的。。。但是现在你的答案有点混乱,XDK是否设置为默认值?这段代码不包括:公共类测试{static{System.out.println(k);k=2;}static int k;公共静态void main(String[]args){System.out.println(k);}}这段代码包括:
公共类测试{static{System.out.println(Test.k);k=2;}static int k;公共静态void main(String[]args){System.out.println(k);}
@EJP:注意2个条件1)最终类变量和2)初始值设定项是编译时常量,这在步骤6中完成。这里没有矛盾。你甚至可以在ideone上查看该节目。