繁体   English   中英

静态final int v / s static int

[英]Static final int v/s static int

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

这段代码打印出5号而不是12号。你能解释一下原因吗? 如果第二个变量也是final变量,你能解释为什么它会打印12,如果它们都不是final变量那么它会打印出来吗?

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;
    }
}

要知道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;
    }
}

非初始化int的默认值为0; 因为你的Q26实例是在var1var2之前声明的, 由于var1首先被初始化(因为它是final ),结果就是你所看到的: ans是5。

与此代码等效的可能是:

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
    }

你班上的静态成员并不是所有人都在同时神奇地初始化。 在引擎盖下,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成员的声明及其初始化已经分开。 将初始化放在静态块中会使这些成员的初始化与其他任何成员一样初始化并具有执行顺序更加明显。

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

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

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

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

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;
    }
}

所以不要误以为你用来声明变量的关键字确保一些特定的执行顺序!

这是因为静态成员的初始化顺序,它们将初始化它们声明的文本顺序。 在该对象变量q26之前定义int变量var1var2 ,如下所示

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


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

现在输出是12

在您的情况下,对象q26在变量var2之前初始化,但var1是最终变量,在编译时知道该值。 所以你得到了答案

来自http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

如果将基本类型或字符串定义为常量并且在编译时已知该值,则编译器会将代码中的常量名称替换为其值。 这称为编译时常量。 如果外部世界中常量的值发生变化(例如,如果立法实际上pi应该是3.975),则需要重新编译使用此常量来获取当前值的任何类。

因此,尽管在静态q26之后定义了该变量,编译器已将每个地方var1替换为5。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM