4

I would like to understand initialization of class instances in various cases..
In JLS-7 Section 12.5, there was no mention of how and when final instance variables were initialized? Can some one point me reference to understand the behaviour in case of instance variables declared as final?

   public class Test {

        public static void main(String args[]){

            Child  c1 = new Child();
        }
    }

    class Parent{
        final int a =30;
        Parent(){
            System.out.println("From super Contsrutor "+a);
            meth();
        }
        void meth(){
             System.out.println("From super");
        }
    }

    class Child extends Parent{
         final  int e=super.a;
         int b=30;
        void meth(){
            System.out.println("From Sub e=" +e+", b="+b);
        }
    }

is giving Output as following

From super Contsrutor 30
From Sub e=0,b=0

Where as

public class Test {

    public static void main(String args[]){

        Child  c1 = new Child();
    }
}

class Parent{
    final int a =30;
    Parent(){
        System.out.println("From super Contsrutor "+a);
        meth();
    }
    void meth(){
         System.out.println("From super");
    }
}

class Child extends Parent{
     final  int e=a;
    void meth(){
        System.out.println("From Sub " +e);
    }
}

is giving Output as

From super Contsrutor 30
From Sub 30
Pushparaj
  • 1,039
  • 1
  • 6
  • 26
  • can you post the actual code? – njzk2 May 14 '14 at 17:45
  • 3
    This code does not currently work, you have no constructors for anything because `a` isn't the name of the Parent class. The `meth()` method is never called, but it creates an output. If you clean up the code we may be able to assist you better. – Octavia Togami May 14 '14 at 17:49
  • Note that removing `final` in the first set of classes doesn't change the output, it only does for the second one. – Jonathan Drapeau May 14 '14 at 17:59
  • In the first code, removing `super` will get you `30` for `e`. Calling instance method in constructor is dangerous as the object is not yet fully initialized (this applies mainly to methods than can be overriden). Also complex processing in constructor is known to have a negative impact on testability. – Engineer2021 May 14 '14 at 18:01
  • https://bugs.openjdk.java.net/browse/JDK-4410323 check this – dharam May 14 '14 at 18:07
  • 1
    @dharam: Not the same. – Engineer2021 May 14 '14 at 18:11

3 Answers3

2

This

final int e = a;

is a constant variable, a constant expression. In the invocation

System.out.println("From Sub e=" +e+", b="+b);

the compiler can replace the use of e with its value, 30.

In

final int e = super.a;

the variable e is not a constant variable, because super.a is not a simple name, and therefore the value cannot and will not be replaced.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • "the compiler can replace the use of e with its value, 30." Where can I find in JLS about this constant variable replacement..it seems implicit but I want to see that in JLS..because if we have like this class Child extends Parent{ final int e=a; int b=a; void meth(){ System.out.println("From Sub,e=" +e+",b="+b); } We get the output 30,0 since b is not final hence not constant variable hence cann't be replaced at compile time. – Pushparaj May 14 '14 at 21:16
  • Also in JLS-7 "At run time, static fields that are final and that are initialized with constant expressions (§15.28) are initialized first (§12.4.2). This also applies to such fields in interfaces (§9.3.1). These fields are "constants" that will never be observed to have their default initial values (§4.12.5), even by devious programs (§13.4.9). " ..but they didn't mention for instance final varaibless... – Pushparaj May 14 '14 at 21:23
  • 1
    @Pushparaj The answer is part of the chapter on String literals and the one on String concatenation. The field `e` _is_ actually initialized in the `Child` constructor after the `Parent` constructor has completed (see byte code), but in a String literal including concatenation of constant expressions, the values are taken as is at compile time and used. – Sotirios Delimanolis May 14 '14 at 21:57
  • 2
    @Pushparaj Look around for how String literals work as constant expressions. Something like [this](http://stackoverflow.com/questions/19418427/comparing-strings-with-which-are-declared-final-in-java/19418517#19418517). – Sotirios Delimanolis May 14 '14 at 21:59
1

first piece of Code is giving the output as below

From super Contsrutor 30
From Sub e=0,b=0

This is because of below reason.

first thing when we do new Child() , the constrcutor of Child class starts execution

but its first statement is super by default so it gives a call to parent class constrctor

now Parent class constrcutor has below code

Parent(){ System.out.println("From super Contsrutor "+a); meth(); }

so here parent class is calling meth() method and its caller is actually a subclass child's object so it calls child class meth() method.

now when it calls child class meth() method from super constrcutor actually child object is not yet created so its variables are not yet initialized but we are printing the values for both a and b.

so b gets 0 before getting assigned after child constrcutor gets execution completed.

so changing your first piece of code like below will give desired output ie putting meth() call inside child constrctor rather than on parent constrcutor.

package com.kb.finalVariables;

public class Test {

    public static void main(String args[]){

        Child  c1 = new Child();
    }
}

class Parent{
    final int a =30;
    Parent(){
        System.out.println("From super Contsrutor "+a);
       // meth();
    }
    void meth(){
         System.out.println("From super");
    }
}

class Child extends Parent{

     final  int e=super.a;
     int b=30;
     public Child() {
        meth();
    }
    void meth(){
        System.out.println("From Sub e=" +e+", b="+b);
    }
}
Karibasappa G C
  • 2,686
  • 1
  • 18
  • 27
1

Lets find out the flow of the program, I have written below code for it:

package com.test;

public class Test {

    public static void main(String args[]) {
        Child c1 = new Child();
    }
}

class Parent {
    final int a = 30;
    static int count = 0;
    {
        System.out.println("Parent initialization block " + ++count);
    }
    Parent() {
        System.out.println("Parent constructor " + ++count);
        // System.out.println("From super Contsrutor " + a);
        meth();
    }
    void meth() {
        // System.out.println("From super");
        System.out.println("Parent meth method " + ++count);
    }
}

class Child extends Parent {
    final int e = super.a;
    int b = 30;
    {
        System.out.println("Child initialization block " + ++count);
    }
    public Child() {
        System.out.println("Child constructor " + ++count);
    }
    void meth() {
        System.out.println("Child meth method " + ++count);
        // System.out.println("From Sub e=" + e + ", b=" + b);
    }
}

Output:

Parent initialization block 1
Parent constructor 2
Child meth method 3
Child initialization block 4
Child constructor 5

First of all remember I have written initialization block for Parent and Child class, which is called before constructor.

Now if you can see from output on creation of Child object first Parent class is loaded into memory, then you have called meth method inside Parent constructor that will call meth method of Child class but Child but at this time initialization block and constructor of Child is not called that means at this time b is not initialized to 30 but to int default value 0, same case with e variable.

Vishrant
  • 15,456
  • 11
  • 71
  • 120