静态最终 int v/s 静态 int

2022-09-01 20:58:33

这个问题取自我的学习指南。有人能解释为什么会这样吗?Java test

此代码打印出数字 5 而不是 12。你能解释一下为什么吗?你能解释一下为什么如果第二个变量也是,它会打印出12,如果它们都不是,它会打印出0?finalfinal

public class Question26 {
    public static void main(String[] args) {
        System.out.println(Q26.q26.ans);
    }
}

class Q26 {
    public static Q26 q26 = new Q26();
    public int ans;
    private static final int var1 = 5;
    private static int var2 = 7;

    public Q26() {
        ans = var1 + var2;
    }
}

答案 1

要知道你在哪里声明字段的一件事是,这些字段是按顺序初始化的;你不能写:static

public class DoesNotCompile
{
    private static final int foo = 1 + bar; // ERROR: bar is not defined
    private static final int bar = 1;

但是,在您的情况下,情况略有不同:

class Q26 {
    // Declared first, but NOT first to be initialized...
    public static Q26 q26 = new Q26();
    public int ans;
    // The honor befalls to this one, since it is declared `final`
    private static final int var1 = 5;
    private static int var2 = 7; // zero until initialized

    public Q26() {
        ans = var1 + var2;
    }
}

未初始化的默认值为 0;由于您的实例是在 和 之前声明的,因为首先初始化(因为它是 ),因此结果是您所看到的:是 5。intQ26var1var2var1finalans

与此代码等效的代码可以是:

class Q26 {
    public static Q26 q26;
    private static final int var1;
    private static int var2;

    static {
        var1 = 5;
        q26 = new Q26();
        var2 = 7;
    }

    public int ans;

    public Q26() {
        ans = var1 + var2;
    }
}

进一步说明:还有静态初始化块;顺序对这些也很重要。您不能执行以下操作:

public class DoesNotCompileEither
{
    static {
        foo = 3; // ERROR: what is foo?
    }
    private static final int foo;

如果将静态初始值设定项放在 的声明下面,则将编译:foo

public class ThisOneCompiles
{
    private static final int foo; // declared
    static {
        foo = 3; // initialized
    }

答案 2

类上的静态成员不会同时神奇地初始化。在引擎盖下,Java必须设置它们 - 它按照你声明的顺序进行设置,除了一个。final

让我们重写一下,这样问题就变得更清晰了:

public class Question26 {
    public static void main(String[] args) {
        System.out.println(Q26.q26.ans);
    }
}
class Q26 {
    public static Q26 q26;
    public int ans;
    private static final int var1 = 5;
    private static int var2;

    static {
        q26 = new Q26();
        var2 = 7;
    }

    public Q26() {
        ans = var1 + var2;
    }
}

在这里,非成员的声明及其初始化已被分开。将初始化放在静态块中可以更清楚地表明,这些成员的初始化与其他任何成员一样是代码,并且具有执行顺序。final static

但是为什么变量之前初始化?看看这个答案Java规范,似乎可能会被视为编译时常量表达式。即使它没有被这样对待,只要它被声明并在一个语句中初始化,就应该由运行时在非变量之前初始化:finalq26var1var1final

在运行时,将首先初始化最终字段和使用常量表达式初始化的静态字段。这也适用于接口中的此类字段。这些字段是“常量”,即使通过狡猾的程序,也永远不会观察到它们具有默认的初始值。

引用:http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.1

那么,如果我们变得疯狂,将成员的声明和初始化分开呢?在这种情况下,我们实际上可以使您的程序编译和执行,只是为了输出 - 这与您在问题中所做的一些断言相矛盾。static finalvar10

public class Question26 {
    public static void main(String[] args) {
        System.out.println(Q26.q26.ans);
    }
}
class Q26 {
    public static Q26 q26;
    public int ans;
    private static final int var1;
    private static int var2;

    static {
        q26 = new Q26();
        var1 = 5;
        var2 = 7;
    }

    public Q26() {
        ans = var1 + var2;
    }
}

因此,不要被愚弄,以为用于声明变量的关键字可以确保某些特定的执行顺序!


推荐