2012-03-12 52 views
10

我有问题了解初始化发生的顺序。这是我认为的顺序:初始化程序块和变量定义等以什么顺序执行? (java)

*Once per 
    1. Static variable declaration 
    2. Static block 
*Once per object 
    3. variable declaration 
    4. initialization block 
    5. constructor 

但根据这个代码,我显然是错误的:

class SomethingWrongWithMe 
    { 
     { 
      b=0;   //no. no error here. 
      int a = b; //Error: Cannot reference a field before it is defined. 
     } 
     int b = 0; 
    } 

而且如果我这样做了错误就会消失:

class SomethingWrongWithMe 
    { 
     int b = 0; 
     { 
      b=0; 
      int a = b; //The error is gone. 
     } 
    } 

我可以不知道为什么没有错误

b=0; 
+0

你使用什么编译器? ORACLE的javac?或者一些IDE(至少Eclipse带有自己的编译器) – 2012-03-12 10:46:48

+0

在这种情况下,Eclipse和Oracles javac的行为相同。 – aioobe 2012-03-12 10:48:12

+1

using eclipse .. – Untitled 2012-03-12 12:55:14

回答

4

Java语言规范(第8.3.2.3)说,你可以在左侧使用变量表达式的右侧,即在声明之前分配给它,但不能在右侧使用它。

所有变量都被初始化为其默认值,然后显式初始值设定项和匿名块按它们在源文件中找到的顺序运行。最后调用构造函数。

静态只在第一次使用类时运行一次。

编译错误似乎是Java的规则,而不是每种情况下都必须有意义的东西。

+0

后续问题: 好的。我现在了解这里的情况。只是无法理解为什么会有这样的功能。我无法想象它的用途。为什么有人想在声明之前在初始化块中分配一个变量?为什么不直接宣布呢? – Untitled 2012-03-13 04:36:54

+1

我同意,为什么我们可以为它分配一个值,但不能读取它? JLS表示,在运行任何显式代码之前,所有变量都被创建并初始化为默认值,所以变量存在且有一个值,我们无法读取它。这对我来说似乎很奇怪。 – 2012-03-13 09:10:16

+0

这样做是为了避免循环引用。例如。 int a = b + 1; int b = a + 2; – ekaerovets 2015-03-06 10:41:31

1

首先,你的假设或多或少是正确的,除了声明(初始化,如int b = 0)和实例初始化块按照它们写入的顺序执行。

int b = 0; // executed first 

{ 
    b = 1; // executed second 
} 

int a = b; // executed third 

还要注意的是声明int b执行。声明声明该变量的存在。

至于你得到的错误(或者,而不是得到的错误得到)我同意它看起来很奇怪。我假定编译器处理在表达式中引用变量并以不同方式为其赋值。在实例初始化程序中写入变量时,它只是检查变量是否存在,而在从中读取变量时,它要求在实例初始化程序块之上声明该变量。我会看看我能否在JLS中找到相关的参考。

3

变量定义没有在“块”之前完成。他们是在同一时间做两中,他们定义的顺序

class SomethingWrongWithMe { 
    { 
     b = debug("block 1"); 
    } 
    int b = debug("define"); 
    { 
     b = debug("block 2"); 
    } 
    private int debug(String str) { 
     System.out.println(str); 
     return 0; 
    } 
} 

输出

block 1 
define 
block 2 
+1

正确,但是为什么他可能会写入一个声明在行下的变量但不能从同一个变量读取的问题没有答案。 – aioobe 2012-03-12 10:42:22