简体   繁体   English

静态final int v / s static int

[英]Static final int v/s static int

This problem was taken from my Java test study guide. 这个问题来自我的Java test学习指南。 Could some explain why this is the way that it is? 有人能解释一下为什么会这样吗?

This code prints out the number 5 and not 12. Could you explain why? 这段代码打印出5号而不是12号。你能解释一下原因吗? Could you explain why it would print out 12 if the second variable was also final , and 0 if neither of them were final ? 如果第二个变量也是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;
    }
}

One thing to know where you declare static fields is that those are initialized in order; 要知道static字段的声明,有一点是按顺序初始化; you cannot write: 你不能写:

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

In your situation, however, things are a little different: 然而,在你的情况下,事情有点不同:

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

The default value of a non initialized int is 0; 非初始化int的默认值为0; since your Q26 instance is declared before var1 and var2 , but since var1 is initialized first (since it is final ), the result is what you see: ans is 5. 因为你的Q26实例是在var1var2之前声明的, 由于var1首先被初始化(因为它是final ),结果就是你所看到的: ans是5。

An equivalent to this code could be: 与此代码等效的可能是:

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

Further note: there are also static initialization blocks; 进一步说明:还有静态初始化块; and order matters for these as well. 并为这些事项订购事宜。 You cannot do: 你做不到:

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

If you put the static initializer below the declaration of foo , then this will compile: 如果你把声明下面的静态初始化foo ,那么这将编译:

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

The static members on your class don't all magically initialize at the same time. 你班上的静态成员并不是所有人都在同时神奇地初始化。 Under the hood, Java has to set them - and it's doing it in the order you declared them, with exception of the final one. 在引擎盖下,Java必须设置它们 - 它按照你声明它们的顺序进行设置,除了final一个。

Lets re-write that so the issue becomes clearer: 让我们重写一下,这样问题就会变得更加清晰:

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

Here the declaration of non- final static members and their initialization have been separated. 这里非final static成员的声明及其初始化已经分开。 Putting the initialization in a static block makes it a little more evident that the initialization of those members is code like any other and has an order of execution. 将初始化放在静态块中会使这些成员的初始化与其他任何成员一样初始化并具有执行顺序更加明显。

But why is the final variable initialized before q26 ? 但为什么final变量在q26之前初始化? Looking at this answer and at the Java specification , it seems that var1 might be getting treated as a compile-time constant expression . 看看这个答案Java规范 ,似乎var1可能被视为编译时常量表达式 Even if it isn't being treated as such though, so long as it is declared and is initialized in one statement, var1 should be initialized by the runtime before the non- final variables: 即使它没有被这样处理,只要它被声明并在一个语句中初始化, var1应该在非final变量之前由运行时初始化:

At run time, static fields that are final and that are initialized with constant expressions are initialized first. 在运行时,首先初始化最终的静态字段以及使用常量表达式初始化的静态字段。 This also applies to such fields in interfaces. 这也适用于接口中的这​​些字段。 These fields are "constants" that will never be observed to have their default initial values, even by devious programs. 这些字段是“常量”,即使是狡猾的程序也永远不会被观察到它们的默认初始值。

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

So what if we get crazy, separating the declaration and initialization of the static final member var1 ? 那么如果我们变得疯狂,将static final成员var1的声明和初始化分开呢? In that case we could actually make your program compile and execute, only to output 0 - which contradicts some of the assertions you made in your question. 在这种情况下,我们实际上可以使您的程序编译和执行,只输出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;
    }
}

So don't be fooled into thinking the keywords you use to declare variables ensures some specific execution order! 所以不要误以为你用来声明变量的关键字确保一些特定的执行顺序!

That is because of the order of initialization of static members, they will be initialized the textual order which they declared. 这是因为静态成员的初始化顺序,它们将初始化它们声明的文本顺序。 Define the int variables var1 and var2 before that object variable q26 like below 在该对象变量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;
    }
}

Now Output is 12 现在输出是12

In your case, the object q26 was initialized before the variable var2 , but var1 is a final vaiable, the value is know at compile time. 在您的情况下,对象q26在变量var2之前初始化,但var1是最终变量,在编译时知道该值。 So you got that answer 所以你得到了答案

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

If a primitive type or a string is defined as a constant and the value is known at compile time, the compiler replaces the constant name everywhere in the code with its value. 如果将基本类型或字符串定义为常量并且在编译时已知该值,则编译器会将代码中的常量名称替换为其值。 This is called a compile-time constant. 这称为编译时常量。 If the value of the constant in the outside world changes (for example, if it is legislated that pi actually should be 3.975), you will need to recompile any classes that use this constant to get the current value. 如果外部世界中常量的值发生变化(例如,如果立法实际上pi应该是3.975),则需要重新编译使用此常量来获取当前值的任何类。

Therefore despite the fact of having that variable defined after the static q26 , the compiler had replaced each place var1 appeared as 5. 因此,尽管在静态q26之后定义了该变量,编译器已将每个地方var1替换为5。

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

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