Will Java Final variables have default values?

13,300

Solution 1

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html, chapter "Initializing Instance Members":

The Java compiler copies initializer blocks into every constructor.

That is to say:

{
    printX();
}

Test() {
    System.out.println("const called");
}

behaves exactly like:

Test() {
    printX();
    System.out.println("const called");
}

As you can thus see, once an instance has been created, the final field has not been definitely assigned, while (from http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.2):

A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared; otherwise a compile-time error occurs.

While it does not seem to be stated explitely in the docs (at least I have not been able to find it), a final field must temporary take its default value before the end of the constructor, so that it has a predictable value if you read it before its assignment.

Default values: http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.5

On your second snippet, x is initialized on instance creation, so the compiler does not complain:

Test() {
    printX();
    x = 7;
    printX();
    System.out.println("const called");
}

Also note that the following approach doesn't work. Using default value of final variable is only allowed through a method.

Test() {
    System.out.println("Here x is " + x); // Compile time error : variable 'x' might not be initialized
    x = 7;
    System.out.println("Here x is " + x);
    System.out.println("const called");
}

Solution 2

JLS is saying that you must assign the default value to blank final instance variable in constructor (or in initialization block which is pretty the same). That is why you get the error in the first case. However it doesn't say that you can not access it in constructor before. Looks weird a little bit, but you can access it before assignment and see default value for int - 0.

UPD. As mentioned by @I4mpi, JLS defines the rule that each value should be definitely assigned before any access:

Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.

However, it also has an interesting rule in regards to constructors and fields:

If C has at least one instance initializer or instance variable initializer then V is [un]assigned after an explicit or implicit superclass constructor invocation if V is [un]assigned after the rightmost instance initializer or instance variable initializer of C.

So in second case the value x is definitely assigned at the beginning of the constructor, because it contains the assignment at the end of it.

Solution 3

If you don't initialize x you'll get a compile-time error since x is never initialized.

Declaring x as final means that it can be initialized only in the constructor or in initializer-block (since this block will be copied by the compiler into every constructor).

The reason that you get 0 printed out before the variable is initialized is due to the behavior defined in the manual (see: "Default Values" section):

Default Values

It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Relying on such default values, however, is generally considered bad programming style.

The following chart summarizes the default values for the above data types.

Data Type   Default Value (for fields)
--------------------------------------
byte        0
short       0
int         0
long        0L
float       0.0f
double      0.0d
char        '\u0000'
String (or any object)      null
boolean     false

Solution 4

The first error is the compiler complaining that you have a final field, but no code to initialize it - simple enough.

In the second example, you have code to assign it a value, but the sequence of execution means you reference the field both before and after assigning it.

The pre-assigned value of any field is the default value.

Solution 5

All non-final fields of a class initialize to a default value (0 for nummeric data types, false for boolean and null for reference types, sometimes called complex objects). These fields initialize before a constructor (or instance initialization block) executes independent of whether or not the fields was declared before or after the constructor.

Final fields of a class has no default value and must be explicitly initialized just once before a class constructor has finished his job.

Local variables on the inside of an execution block (for example, a method) has no default value. These fields must be explicitly initialized before their first use and it doesn't matter whether or not the local variable is marked as final.

Share:
13,300

Related videos on Youtube

user3766874
Author by

user3766874

Updated on June 02, 2022

Comments

  • user3766874
    user3766874 about 2 years

    I have a program like this:

    class Test {
    
        final int x;
    
        {
            printX();
        }
    
        Test() {
            System.out.println("const called");
        }
    
        void printX() {
            System.out.println("Here x is " + x);
        }
    
        public static void main(String[] args) {
            Test t = new Test();
        }
    
    }
    

    If I try to execute it, i am getting compiler error as : variable x might not have been initialized based on java default values i should get the below output right??

    "Here x is 0".
    

    Will final variables have dafault values?

    if I change my code like this,

    class Test {
    
        final int x;
    
        {
            printX();
            x = 7;
            printX();
        }
    
        Test() {
            System.out.println("const called");
        }
    
        void printX() {
            System.out.println("Here x is " + x);
        }
    
        public static void main(String[] args) {
            Test t = new Test();
        }
    
    }
    

    I am getting output as:

    Here x is 0                                                                                      
    Here x is 7                                                                                     
    const called
    

    Can anyone please explain this behavior..

  • JamesB
    JamesB almost 10 years
    The final variable x is not static in the OP's code.
  • Michael D.
    Michael D. almost 10 years
    I could just as easily modify the OP's code to initialize to this.x and the same thing would happen. It does not matter if it's static or not.
  • JamesB
    JamesB almost 10 years
    I would suggest you remove the static content here as it looks like you haven't read the OP's question.
  • Michael D.
    Michael D. almost 10 years
    Does it help if I baseline from the OP's code then? As I said, it doesn't matter if the variable is static or not. My point is that initializing a variable to itself and getting the default value implies that the variable does get implicitly initialized before being explicitly initialized.
  • l4mpi
    l4mpi almost 10 years
    Actually, it does say you can not access it before assignment: "Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs"
  • udalmik
    udalmik almost 10 years
    it should be "definitely assigned", however this rule has strange behavior in terms of constructor, I have updated the answer
  • supercat
    supercat almost 10 years
    If there is a method of code which, depending upon some complex conditions, may or may not read a final field, and if that code may be run both before and after the field is written, a compiler would in the general case have no way of knowing whether it would ever in fact read the field before it was written.
  • Patrick
    Patrick almost 10 years
    It might be worth noting where the implicit (or explicit) call to super() goes in one of your examples.
  • justhalf
    justhalf almost 10 years
    This doesn't answer why not initializing final field causes a compile error.
  • Bohemian
    Bohemian almost 10 years
    @sp00m Good reference - I will put that in the bank.
  • Luca
    Luca almost 9 years
    it doesn't compile,because you're attempting to access (directly) a final variable before it's initialized,on line 6.
  • Luca
    Luca almost 9 years
    @justhalf the answer is missing a crucial point. You can access a final in its default state (through a method) ,but the compiler will complain if you don't initialize it before the end of the construction process. That's why the second attempt works (it actually initialize x),but not the first one. The compiler will also complain if you try to access a blank final directly.