Monday, December 8, 2014

Keynote: Variables initialization

Variable names can beginning only with a letter, the dollar sign `$`, or the
underscore character 
`_`.

First of all u have to be familiar with Initialization-order-flow


Let's start from the smallest scope:

Local variables

Compiler never assigns default values to an uninitialized LOCAL variables.
Actually compiler will pass not initialized local variable if it's never used.
However u'll receive Compile error: "Error: java: variable `localVariable` might not have been initialized" if u'll try to use not initialized local variable.

So, if u can't initialize your local variable where it's declared, make sure to assign it a value before you attempt to use it.

Instance variables

Compiler assigns default values to INSTANCE variables.

type value
boolean false
byte 0
short 0
int 0
long 0L
char \u0000
float 0.0f
double 0.0d
object reference null

Instance constants (final variables)

U have to assign value to your final instance variable only once in the following places:
  • during declaration;
  • in instance initializer block;
  • in constructor.
Otherwise, u'll receive Compile error: "Error: java: variable `instanceConst` might not have been initialized" even if this final instance variable is never used.
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.
(jls §8.3.1.2.)

Class variables

STATIC fields will be initialized in their declaration order:

public class VariablesInitOrderProof{
    
    private static int staticVariable1 = 1; 

    static { 
        System.out.println("1st Static initializer"); 
        staticVariable1 = 2;
    } 
    
    static { 
        System.out.println("2nd Static initializer"); 
        staticVariable2 = 1;
    } 
    
    private static int staticVariable2 = 2; 

    public VariablesInitOrderProof() { 
        System.out.println("class Constructor."); 
        System.out.println("staticVariable1 = " + staticVariable1);
        System.out.println("staticVariable2 = " + staticVariable2);
    }   

    { System.out.println("Instance initializer"); }    

    public static void main(String[] args) {
          System.out.println("App Main");                
          new InitOrderProof();
    } 
}

output:
1st Static initializer.
2nd Static initializer. 
App Main
Instance initializer
class Constructor. staticVariable1 = 2 staticVariable2 = 2
Cause it's similar to the following:

public class VariablesInitOrderProof{
    
    private static int staticVariable1; 

    static {
        staticVariable1 = 1;
        staticVariable1 = 2;
    } 
    
     static {
        staticVariable2 = 1;
        staticVariable2 = 2;
     } 
    
    private static int staticVariable1; 

    public VariablesInitOrderProof() { 
        System.out.println("class Constructor."); 
        System.out.println("staticVariable1 = " + staticVariable1);
        System.out.println("staticVariable2 = " + staticVariable2);
    }   

    public static void main(String[] args) {               
          new InitOrderProof();
    } 
}

So, Compiler will assign the default value to your static variable if u won't assign it by yourself:

public class VariablesInitOrderProof{
    
    private static int staticVariable1; 

    static {
        System.out.println("1st Static initializer. staticVariable1 =" + staticVariable1);   // output `0`
    } 
    ...
}

However it will not allow you to read it before it was declared:

public class VariablesInitOrderProof{
    
    static {
        System.out.println("1st Static initializer. staticVariable2 =" + staticVariable2);   // Compile-error: illegal forward reference
    } 

    private static int staticVariable2;
    ...
}

Class constants (static final variables)

U have to assign value to your final instance variable only once in the following places:
  • during declaration;
  • in instance initializer block.  (in constructor)
Otherwise, u'll receive Compile error: "Error: java: variable `instanceConst` might not have been initialized" even if this final instance variable is never used.
A FINAL variable may only be assigned once!
Each class variable, instance variable, or array component is initialized with a default value when it is created:

public class VariablesInitOrderProof{
    
    private static final int CLASS_CONSTANT; 
    
    static {
        printClassConstant();
        CLASS_CONSTANT = 2;
        printClassConstant();
    } 

    public static void printClassConstant() {
        System.out.println("CLASS_CONSTANT = " + CLASS_CONSTANT);
    }
    ...
}

output:
CLASS_CONSTANT = 0
CLASS_CONSTANT = 2
However, Compiler won't allow you explicitly use blank(not assigned) final variable, cause it's value treated as compile-time constant expression.
It is a compile-time error if a blank FINAL class variable is not definitely assigned by a static initializer of the class in which it is declared.(jls §8.3.1.2.)

Conclusion

All member variables have to load into heap so they have to be initialized with default values when an instance of class is created. In case of local variables, they don't get loaded into heap they are stored in stack until they are being used before java 7, so we need to explicitly initialize them. Now the "Java Hotspot Server Compiler" performs "escape analysis" and decides to allocate some variables on the stack instead of the heap.
And u have to assign once and manually final variables before usage.


jls §8.3.2.1. Initializers for Class Variables
jls §8.3.1.2. final Fields

jls §12.4.2. Detailed Initialization Procedure

No comments:

Post a Comment