在Java中对此结果的解释是什么?

时间:2010-06-08 21:33:19

标签: java

我有以下代码:

public class Main {
    private int i = j; //1
    private int j = 10; 

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

并且第1行中存在编译器错误,因为它是非法的 前瞻性参考 但是当我尝试以下代码时:

public class Main {
    int i = getJ();  //1

    int getJ(){
       return j;
    }
    int j=10;
    public static void main(String[] args) {
        System.out.println(new Main().i);
    }
}

它工作正常,结果为0.
为什么没有非法 这里第1行的前向参考?这两个代码与我类似。

5 个答案:

答案 0 :(得分:6)

可以在声明方法之前使用方法。

private int j = 10;是一个必须在某个时间点执行的可执行语句。因此,字段声明的顺序是有意义的。

方法声明本身不可执行 因此,方法的排序完全没有意义。

答案 1 :(得分:4)

该规则仅适用于字段。具体来说(JLS 8.3.2.3):

  

成员的声明需要   在使用之前以文本方式显示   仅当成员是实例时   一个类的(分别是静态的)字段   或接口C和所有的   以下条件成立:

     
      
  • 用法发生在实例(分别是静态)变量中   C的初始化程序或实例   (分别是静态的)初始化器   下进行。
  •   
  • 用法不在作业的左侧。
  •   
  • 使用方法是一个简单的名称。
  •   
  • C是封闭用法的最里面的类或接口。
  •   

第一个例子的所有条件都适用。

  1. j是一个实例字段。
  2. 我是一个实例字段。
  3. j用于右侧。
  4. j是一个简单的名称(基本上,该字段是直接使用的)
  5. 主要是封闭两者的最内层的课程。
  6. 至少有一个(“通过简单名称使用”)不适用于第二个示例。基本上,编译器尝试捕获循环错误,如:

    int i = j + 1;
    int j = i + 1;
    

    这有点过于谨慎,但它大部分都有效。在执行j = 10之前,j仍为0,因此i的值被设置为。没有办法扩展你的getJ示例来创建一个循环(当然,还有其他方法可以在运行时创建无限递归)。

答案 2 :(得分:2)

因为您在实例初始化完成之前显式调用方法并访问成员变量。编译器可以阻止你做多么愚蠢的事情是有限的! : - )

答案 3 :(得分:2)

Java运行时有一个信息,你有一个实例变量,它是int,称为“j” 但是,在字节码解释器到达初始化之前,该值不会设置为10。

这就是您将默认int值视为返回值的原因。

答案 4 :(得分:0)

J在被引用以进行赋值之前未被声明