Internal working of static and non-static forward references in Java

229 Views Asked by At

I am working with forward references in Java and wondering why Java allows forward reference with either ClassName (in static variable) or with this reference in case of instance variable? What is the background process that is taking place at the level of JVM? For instance:

Static Forward Reference-

class StaticForwardReferences {
    static {
        sf1 = 10;   // (1)
        int b = sf1 = 20;   // (2)
        int c = StaticForwardReferences.sf1; // (3) Works fine
        // Above statement allows the allocation of value of 'sf1'
        // to variable 'c' just because it is accessed with class name
        // instead of direct name

        // whereas below statement throws illegal forward reference
        // error at compile time
        System.out.println(sf1); // (4) Illegal forward reference
    }
    static int sf1 = sf2 = 30;
    static int sf2;

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

Is there any kind of temporary storage where the values get stored when we do a forward reference by assigning the variables before their declaration as done in (1) and (2) steps above, if we print the value of variable c, it shows the value from the most recent assignment did to sf1.

Non-static Forward Reference-

class NonStaticForwardReferences {
    {
        nsf1 = 10;
        System.out.println(this.nsf1);  // 10
        nsf1 = sf1;
        // System.out.println(nsf1); Illegal forward reference
        int b = nsf1 = 20;

        int c = this.nsf1;
        System.out.println(c);  // 20
        // why variable 'c' is initialized to 20 when used with 'this' reference
        // instead of showing illegal forward reference, how it works in the background?
   }

   int nsf1 = nsf2 = 30;
   int nsf2;
   static int sf1 = 5;

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

Please put some light on the background process that is taking place behind the scenes for the above two cases. Thanks in advance! :)

3

There are 3 best solutions below

1
On

Java requires that the declaration of a field must occur before its usage in any initializer expression if the field is used on the right-hand side of an assignment in the initializer expression. This essentially means that the declaration of a field must occur before the value of the field is read in an initializer expression.

When making forward references using simple names, code in a static initializer block is also subject to the declaration-before-reading rule discussed above.

As in an instance initializer expression, the keywords "this" and "super" can be used to refer to the current object in an instance initializer block.

2
On

The JLS, Section 8.3.3, states the conditions for making a forward reference to a static variable (a "class variable") a compiler error, although it doesn't state the reasoning.

Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:

  • The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  • The use is a simple name in either a class variable initializer of C or a static 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.

(italic emphasis mine)

The instance variables forward reference error appears with similar conditions:

Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables are in scope. Specifically, it is a compile-time error if all of the following are true:

  • 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.

(italic emphasis mine)

In both cases, using a simple name is the key condition here. That means using the variable without any qualifier such as this or a class name. This is why this.nsf1 works in NonStaticForwardReferences. If you remove this, then the error occurs. This is also why sf1 has the error and StaticForwardReferences.sf1; does not have the error.

0
On

The prohibition on forward references does not imply that variables are created when initialized. The “background process” is just that classes and objects are allocated all at once, with the (static) variables being given default values. (Which is to say “zero”: it’s probably implemented with calloc or memset in practice.)

The forward reference rules are meant to prevent seeing these first values, especially for final variables which supposedly ever have only one value. But they exist to catch human error and are themselves not perfect: only for constant variables does the initialization happen so early that the default values are unobservable. Specifying this or a class name explicitly is the simplest way of demonstrating this effect.