4

Here is the code:

public class Main {
    public static void main(String[] args) {
        new B();
    }
}

class A {
    A() {
        System.out.println("A constructor before");
        action();
        System.out.println("A constructor after");
    }

    protected void action() {
        System.out.println("Never called");
    }
}

class B extends A {
    private final int finalField = 42;
    private int field = 99;

    B() {
        System.out.println("B constructor");
        action();
    }

    public void action() {
        System.out.println("B action, finalField=" + finalField + ", field=" + field);
    }
}

And the result is:

A constructor before
B action, finalField=42, field=0
A constructor after
B constructor
B action, finalField=42, field=99

I confused by this line :

B action, finalField=42, field=0

Object B is not completely initialized and when we call method "action" from super class constructor - variable "field" has a default value, but the final variable "finalField" already has value 42.

When was the "finalField" initialized?

  • The link from Turing has the answer, but great question with clear formatting. – sorifiend Aug 16 '20 at 11:25
  • 1
    The dupe seems incorrect to me, it doesn't seem to explain the seemingly different initialization orders of `field` and `finalField`. (Looking at the byte code, both field and finalField are initialized in B's constructor after calling A's constructor, so something else is going on here). Voting to reopen – Jorn Vernee Aug 16 '20 at 11:45
  • Thank you! I read the article by the link [https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5], but I still have a question remains why final variable does not set to a default value (in this case 0). – Roman Frolov Aug 16 '20 at 11:45
  • Look at the bytecode and see what's different between the normal and the final field – Lino Aug 16 '20 at 12:03

2 Answers2

5

When a final field is initialized with a constant expression (15.29), it's called a constant variable (4.12.4):

private final int finalField = 42;

This means that the string

"B action, finalField=" + finalField + ", field="

is a constant expression itself and its value is determined at compile time. If you inspect the compiled class file you will in fact find the string B action, finalField=42, field= in the constant pool section.

In general, when a field that is a constant variable is used, it has to be replaced by its value at compile time. It is not allowed (13.1) to reference the field at run time:

  1. A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

    If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).

The field initializer still runs when you would expect: after A constructor has returned and before B constructor starts. Observing the uninitialized value is tricky because the compiler inlines the uses of the variable, but you can access the value of the field through reflection:

public void action() {
    try {
        System.out.println("B action, finalField="
            + getClass().getDeclaredField("finalField").get(this)
            + ", field=" + field);
    } catch (IllegalAccessException | NoSuchFieldException e) {
        e.printStackTrace();
    }
}

Output:

A constructor before
B action, finalField=0, field=0
A constructor after
B constructor
B action, finalField=42, field=99
Joni
  • 108,737
  • 14
  • 143
  • 193
1

In java there are two types of flows .

  1. Static flow
  2. Instance flow

Static Flow

Whenever we are executing Parent Child Class the following sequence of events will be performed automatically.

  • Identification of static Members from Parent to Child

  • Execution of Static Variable Assignments and static blocks from parent to child

  • Execution of Only Child class main

Instance Flow

  • Whenever we are executing a Java class static control flow will be executed first.

  • Identification of Instance Members from Parent to Child

  • Execution of Instance variable assignments and instance block only in parent class

  • Execution of Parent Class Constructor

  • Execution of Instance variable assignments and instance blocks in child class

  • Execution of child class constructor

Based on these rules i will try to explain how jvm executes your code .

  1. Identifies static member:-> public static void main(String[] args) ;

  2. Execute main method

  3. Identify instance members in A class first and then B class

//A class members

protected void action();

//B class members

private final int finalField =42; (since this is final complier will direclty assing it )

private int field =0;(add default values for this member)

public void action();

  1. Execution of Instance variable assignments and instance blocks only in parent

// no member to assign

  1. Execute Parent Construcor

    First line in B constructor is super() so the control will go in A class constructor.

    System.out.println("A constructor before")

    action(); //This is little bit tricky ,since the both methods are already identified by the compiler jvm has two options to choose ,action() in A class or action() B ,but .since action method is overriden in B class and java for overriden methods uses Runtime Polimorifizem rule ,it will execute action() method in B classs

    // at this time value of field is 0

    System.out.println("A constructor after")

  2. Execution of Instance variable assignments and instance blocks only in child class

private int field =99

  1. Execute child class constructor
Mirjan Gjeta
  • 139
  • 3
  • Sort of, thank you. I need to reed more about it. Have problem with understanding “final” case – Roman Frolov Aug 16 '20 at 13:35
  • @RomanFrolov for final case i think it is easy . You just need to know that every final variable is evaluated during compile time before jvm stars execution of the program . – Mirjan Gjeta Aug 16 '20 at 14:26