4

这是Java。我知道 1 的分配index是在initialization block实例化类时首次运行的,但为什么这是有效的?

public class arr {
    {
        index = 1;
    }

    int index;

    void go() {
        System.out.println(++index);
    }
    public static void main(String [] args){
          new arr().go(); 
        }
    }

输出为 2。

我应该得到一个symbol not found编译错误。这种行为是初始化块固有的吗?在正常情况下int index;应该来之前index = 1;

4

7 回答 7

5

+1,看起来真的很奇怪。但事实上,非静态初始化块只是由 javac 插入到对象构造函数中。如果我们反编译 arr.class 我们将得到真正的代码

public class arr {
    int index;

    public arr() {
        index = 1;
    }

    void go() {
        System.out.println(++index);
    }

    public static void main(String args[]) {
        (new arr()).go();
    }

}

让更多的乐趣考虑这个难题

public class A {
    int index;

    A() {
        index = 2;
    }

    {
        index = 1;
    }
}

什么是新的 A().index ?正确答案是2。见反编译的A.class

class A {
    int index;

    A() {
        index = 1;
        index = 2;
    }
}

也就是说,非静态初始化块首先出现在对象构造函数中

于 2012-12-30T10:42:53.077 回答
4

非静态初始化块在构造函数之后立即运行,因此代码正确且输出符合预期。

于 2012-12-30T10:36:34.113 回答
4

代码的顺序无关紧要。正如您所说,

在正常情况下 int 索引;应该在 index = 1 之前;

这正是声明该字段然后分配值 1 所发生的情况。编译器不关心类中这些项目的物理顺序。

于 2012-12-30T10:36:51.987 回答
2

Java Tutorial中,Java 编译器将初始化程序块复制到每个构造函数中。因此,这种方法可用于在多个构造函数之间共享代码块。

下面是使用 final 方法初始化实例变量的示例:

    class Whatever {
        private varType myVar = initializeInstanceVariable();

        protected final varType initializeInstanceVariable() {

            // initialization code goes here
        }
    }
于 2012-12-30T10:38:32.453 回答
1

Java 教程指出:

一个类可以有任意数量的静态初始化块,它们可以出现在类主体的任何位置。

此外,变量也是如此,您可以在声明它们之前“使用”它们:

class T {

    public static void main(String[] args) {
        T t = new T();
        System.out.println(t.a);
    }

    public int a = 14;
} 
于 2012-12-30T10:40:55.130 回答
1

与某些语言(例如 C)不同,类(静态)变量和实例变量的声明顺序在 Java 中是不相关的。您可以在声明之前(以文本方式)引用类/实例变量。所以即使这是有效的......

public class X {
   private int a = b;
   private int b = a;
   ...
}

...虽然初始化程序实际上并没有实现任何有用的东西。

于 2012-12-30T11:47:47.277 回答
0

Java 是一种在执行任何特技之前完全解析您的代码的语言(我试图避免无聊的编译器细节)。因此,如果您的初始化程序块出现在字段声明之前,则无关紧要,事情发生的特定顺序。类加载(当然还有字段加载)、静态初始化程序、构造函数、非静态初始化程序都在任何方法调用之前运行(可以在不执行构造函数和非静态成员的情况下执行静态调用)。您应该考虑阅读一些 SCJP(现在的 OCPJP)书籍,例如“K&B”,以真正了解幕后发生的事情。在这个阶段,像“JVM internals”这样的教程可能有点过头了(但你应该考虑将它保存在你的存档中以供以后参考)。

于 2012-12-30T10:50:24.190 回答