gameover
gameover

Reputation: 12023

Using final methods to initialize an instance variable

From the Sun docs

Normally, you would put code to initialize an instance variable in a constructor.
There are two alternatives to using a constructor to initialize instance variables: initialize blocks and final methods.

I could understand the use of initialize blocks. Can anyone please explain the use of final methods for instance var initialization? A non-final public setter can do this job. Why not just use them ?

Upvotes: 17

Views: 2988

Answers (3)

ROMANIA_engineer
ROMANIA_engineer

Reputation: 56666

Other examples

From alykhantejani.github.io

I made it compilable and simplified it.

Duck.java

public class Duck {

    String sound = "quack";
    protected String speech;

    public Duck() {
        initSpeech();
    }

    protected void initSpeech() {
        speech = "sound = " + sound;
    }

    public void speak() {
        System.out.println(speech);
    }

    protected String getSound() {
        return sound;
    }
}

SqueakyDuck

public class SqueakyDuck extends Duck {

    String squeakSound = "squeak";

    public SqueakyDuck() {
        super();
    }

    @Override
    protected void initSpeech() {
        speech = "sound = " + squeakSound;
    }

    @Override
    protected String getSound() {
        return squeakSound;
    }
}

Main.java

public class Main {

    public static void main(String[] args){
        Duck squeaky = new SqueakyDuck();
        squeaky.speak();
        System.out.println(squeaky.getSound());
    }
}

Output:

sound = null
squeak

My example

Superclass.java

public class Superclass {

    protected int x = m();

    protected int m() {
        return 8;
    }

}

Subclass.java

public class Subclass extends Superclass {

    private int y = 7;

    @Override
    protected int m() {
        return y;
    }

}

Main.java

public class Main {
    public static void main(String[] args) {
        Superclass s = new Subclass();
        System.out.println(s.x);
    }
}

Output:

0

Order of execution:

  • main
  • m from Subclass (y is not initialized in this moment and 0 is the default value for int)
  • constructor Superclass
  • constructor Subclass

Upvotes: 3

Andreas Dolk
Andreas Dolk

Reputation: 114787

It's explained on the same page of the referenced tutorial. The reason is that a non-final method can be overriden by up subclass. Here's an example:

class Whatever {
    private List<String> myVar = initializeInstanceVariable();

    protected List<String> initializeInstanceVariable() {
        return new ArrayList<String>();
    }
}

class Whoever extends Whatever {

    @Override
    protected List<String> initializeInstanceVariable() {
       return Collections.unmodifiableList(super.initializeInstanceVariable());
    }

}

So if you create Whoever, myVar will become unmodifiable ;-)

Upvotes: 4

BalusC
BalusC

Reputation: 1108742

The advantage is already described in the very same Sun tutorial you linked to:

A final method cannot be overridden in a subclass. This is discussed in the lesson on interfaces and inheritance.

This is especially useful if subclasses might want to reuse the initialization method. The method is final because calling non-final methods during instance initialization can cause problems. Joshua Bloch describes this in more detail in Effective Java(item 17 Design and document for inheritance).

The reason a non-final method is dangerous in initialization is because the instance initialization of the superclass executes before the sub class is initialized. Therefore if the non-final method is overriden in the sub class and is executed during the initialization of the superclass it may be accessing uninitialized fields of the subclass giving erroneous results.

The general rule is(quoting from Effective Java): Constructors must not invoke overridable methods, directly or indirectly.

Upvotes: 27

Related Questions