Featured imaged

A typical scenario when creating a new class is to declare and initialize some fields:

public class Values {

    private int value1 = 1;
    private int value2 = 2;

}

I realize that initial values of these fields are correlated and I update the code:

public class CorrelatedValues {

    private int value1 = 1;
    private int value2 = value1 + 1;

}

If I’m not careful, I can even try:


public class ForwardReferences {

    private int value1 = value2 + 1;
    private int value2 = 1;

}

but this won’t compile because it is a forward reference during field initialization:

  • The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
  • The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
  • The use is not on the left hand side of an assignment;
  • C is the innermost class or interface enclosing the use.

It is easy to understand even without this documentation because it’s commons sense. I need to declare a variable before I can use it. This was clear for me until I saw this code:

public class DeclarationAndInitializationGoCrazy {

    private int value = this.value + 1;

    public static void main(String... args) {
        System.out.println(new DeclarationAndInitializationGoCrazy().value);
    }

}

Surprisingly this code compiles and displays:

1

The question is why is this working? I would expect a compile time error. After reading more careful the rules about forward reference during field initialization, the catch is on the second line:

  • The use is a simple name in either an instance variable initializer of C or an instance initializer of C;

In this example I’m using this.value and not the simple name value and that’s why it works. What really happens when creating a new instance of DeclarationAndInitializationGoCrazy is:

  • Field value is set to default value 0
  • Field value is initialized with 0 + 1 which is 1

I can go really crazy and try something like:

public class DeclarationAndInitializationReallyGoCrazy {

    private int value1 = this.value2 + 1;
    private int value2 = this.value1 + 1;

    public static void main(String... args) {
        System.out.println(new DeclarationAndInitializationReallyGoCrazy().value1);
        System.out.println(new DeclarationAndInitializationReallyGoCrazy().value2);
    }

}

that compiles and displays:

1
2

It is the same explanation as on previous example:

  • Fields value1 and value2 are set to default value 0
  • Field value1 is initialized with 0 + 1 which is 1
  • Field value2 is initialized with 1 + 1 which is 2

I don’t see now any practical reason why I would do this in a real project code, at least it was a fun thing to do.

Image credit: cristofer angello caballero thorne, CC0 Public Domain