简体   繁体   中英

Initialization of static final fields in Java

public class Main {
 static final int alex=getc();
 static final int alex1=Integer.parseInt("10");
 static final int alex2=getc();

public static int getc(){
    return alex1;
}

public static void main(String[] args) {
    final Main m = new Main();
    System.out.println(alex+" "+alex1 +" "+alex2);
  } 
}

Can someone tell me why this prints: 0 10 10 ? I understand that it's a static final variable and its value shouldn't change but it`sa little difficult to understand how the compiler initializes the fields.

It's an ordering problem. Static fields are initialized in the order that they are encountered, so when you call getc() to inititalize the alex variable, alex1 hasn't been set yet. You need to put initialization of alex1 first, then you'll get the expected result.

Static final fields whose values are not compile-time constant expressions are initialized in order of declaration. Thus when alex in being initialized, alex1 is not initialized yet, so that getc() returns default values of alex1 ( 0 ).

Note that result will be different ( 10 10 10 ) in the following case:

static final int alex1 = 10;

In this case alex1 is initialized by a compile-time constant expression, therefore it's initialized from the very beginning.

This situation is covered by JLS 8.3.2.3 "Restrictions on the use of Fields during Initialization".

The JLS rules allows the usage in your Question, and state that the first call to getc() will return default (uninitialized) value of alex .

However, the rules disallow some uses of uninitialized variables; eg

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

is disallowed.


Re some of the other answers. This is not a case where the Java compiler "can't figure it out". The compiler is strictly implementing what the Java Language Specification specifies. (Or to put it another way, a compiler could be written to detect the circularity in your example and call it a compilation error. However, if it did this, it would be rejecting valid Java programs, and therefore wouldn't be a conformant Java compiler.)


In a comment you state this:

... final fields always must be initialized at compile or at runtime before the object creation.

This is not correct.

There are actually two kinds of final fields:

  • A so-called "constant variable" is indeed evaluated at compile time. (A constant variable is a variable "of primitive type or type String, that is final and initialized with a compile-time constant expression" - see JLS 4.12.4.). Such a field will always have been initialized by the time you access it ... modulo certain complications that are not relevant here.

  • Other final fields are initialized in the order specified by the JLS, and it is possible to see the field's value before it has been initialized. The restriction on final variables is that they must be initialized once and only once during class initialization (for a static ) or during object initialization.


Finally, this stuff is very much "corner case" behavior. A typical well-written class won't need to access a final field before it has been initialized.

There is nothing special about static fields, it just that the compiler cannot workout that you are using a method which can access a field before its initialised.

eg

public class Main {
    private final int a;

    public Main() {
        System.out.println("Before a=10, a="+getA());
        this.a = 10;
        System.out.println("After a=10, a="+getA());
    }

    public int getA() {
        return a;
    }

    public static void main(String... args) {
        new Main();
    }
}

prints

Before a=10, a=0
After a=10, a=10

Class variables are not necessary to initialize, they are automatically set to their default values. If primitives (like int, short...) it's 0 (zero) for Objects it's null . Therefore alex1 is set to 0. Method variables must be initialized, otherwise you will get an compiliation error.

For a better explanation read http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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