How Is an Instance Initializer Different from a Constructor

How is an instance initializer different from a constructor?

This seems to explain it well:

Instance initializers are a useful alternative to instance variable
initializers whenever:

  • initializer code must catch exceptions, or

  • perform fancy calculations that can't be expressed with an instance variable initializer. You could, of course, always write such code in
    constructors.


But in a class that had multiple constructors, you would have to repeat the code in each constructor. With an instance initializer, you
can just write the code once, and it will be executed no matter what
constructor is used to create the object. Instance initializers are
also useful in anonymous inner classes, which can't declare any
constructors at all.

From: JavaWorld Object initialization in Java.

What's the difference between an instance initializer and a constructor?

The code inside the braces with no names will be part of the constructor of the class and be executed before the logic contained in the class constructor.

Quick example:

public class Foo {
{
System.out.println("Before Foo()");
}

public Foo() {
System.out.println("Inside Foo()");
}

{
System.out.println("Not After Foo()");
}
}

Use of Initializers vs Constructors in Java

Static initializers are useful as cletus mentioned and I use them in the same manner. If you have a static variable that is to be initialized when the class is loaded, then a static initializer is the way to go, especially as it allows you to do a complex initialization and still have the static variable be final. This is a big win.

I find "if (someStaticVar == null) // do stuff" to be messy and error prone. If it is initialized statically and declared final, then you avoid the possibility of it being null.

However, I'm confused when you say:

static/instance initializers can be used to set the value of "final"
static/instance variables whereas a constructor cannot

I assume you are saying both:

  • static initializers can be used to set the value of "final" static variables whereas a constructor cannot
  • instance initializers can be used to set the value of "final" instance variables whereas a constructor cannot

and you are correct on the first point, wrong on the second. You can, for example, do this:

class MyClass {
private final int counter;
public MyClass(final int counter) {
this.counter = counter;
}
}

Also, when a lot of code is shared between constructors, one of the best ways to handle this is to chain constructors, providing the default values. This makes is pretty clear what is being done:

class MyClass {
private final int counter;
public MyClass() {
this(0);
}
public MyClass(final int counter) {
this.counter = counter;
}
}

Static Initializers vs Instance Initializers vs Constructors

The main difference between them is the order they are executed. To illustrate, I will explain them with an example:

public class SomeTest {

static int staticVariable;
int instanceVariable;

// Static initialization block:
static {
System.out.println("Static initialization.");
staticVariable = 5;
}

// Instance initialization block:
{
System.out.println("Instance initialization.");
instanceVariable = 10;
}

// Constructor
public SomeTest() {
System.out.println("Constructor executed.");
}

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

The output will be:

Static initalization.
Instance initialization.
Constructor executed.
Instance initialization.
Constructor executed.

Briefly talking:

  • Static initialization blocks run once the class is loaded by the JVM.
  • Instance initialization blocks run before the constructor each time you instantiate an object.
  • Constructor (obviously) run each time you instantiate an object.

static block vs initializer block vs constructor in inheritance

A static block is called once, when the class is loaded and initialized by the JVM. An instance initializer is executed when an instance of the class is constructed, just like a constructor.

Static and Instance initializers are described in the Java Language Specification

Why can my instance initializer block reference a field before it is declared?

From docs:

The Java compiler copies initializer blocks into every constructor.
Therefore, this approach can be used to share a block of code between
multiple constructors.

The above statement is slightly misleading, because if we follow the explanation of the above doc we can rewrite the original code like this:

public class WrongVersionOfWhyIsThisOk {

int a = 10;

public WhyIsThisOk (){
a = 5;
}

public static void main(String[] args){
WrongVersionOfWhyIsThisOk why = new WrongVersionOfWhyIsThisOk ();
System.out.println(why.a);
}
}

But running WrongVersionOfWhyIsThisOk will produce 5 instead of 10 that original code produces.

But in reality it is both the initializer block and variable assignment are copied into constructor:

public class RightVersionOfWhyIsThisOk {

int a;

public RightVersionOfWhyIsThisOk (){
a = 5;
a = 10;
}

public static void main(String[] args){
RightVersionOfWhyIsThisOk why = new RightVersionOfWhyIsThisOk ();
System.out.println(why.a);
}
}

Update:

Here is the doc describing in detail the initialization order and constructor invocation:

4) Execute the instance initializers and instance variable
initializers for this class, assigning the values of instance variable
initializers to the corresponding instance variables, in the
left-to-right order in which they appear textually in the source code
for the class. If execution of any of these initializers results in an
exception, then no further initializers are processed and this
procedure completes abruptly with that same exception. Otherwise,
continue with step 5.

5) Execute the rest of the body of this constructor. If that execution
completes abruptly, then this procedure completes abruptly for the
same reason. Otherwise, this procedure completes normally.

What's the difference between an object initializer and a constructor?

Object Initializers were something added to C# 3, in order to simplify construction of objects when you're using an object.

Constructors run, given 0 or more parameters, and are used to create and initialize an object before the calling method gets the handle to the created object. For example:

MyObject myObjectInstance = new MyObject(param1, param2);

In this case, the constructor of MyObject will be run with the values param1 and param2. These are both used to create the new MyObject in memory. The created object (which is setup using those parameters) gets returned, and set to myObjectInstance.

In general, it's considered good practice to have a constructor require the parameters needed in order to completely setup an object, so that it's impossible to create an object in an invalid state.

However, there are often "extra" properties that could be set, but are not required. This could be handled through overloaded constructors, but leads to having lots of constructors that aren't necessarily useful in the majority of circumstances.

This leads to object initializers - An Object Initializer lets you set properties or fields on your object after it's been constructed, but before you can use it by anything else. For example:

MyObject myObjectInstance = new MyObject(param1, param2)
{
MyProperty = someUsefulValue
};

This will behave about the same as if you do this:

MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;

However, in multi-threaded environments the atomicity of the object initializer may be beneficial, since it prevents the object from being in a not-fully initialized state (see this answer for more details) - it's either null or initialized like you intended.

Also, object initializers are simpler to read (especially when you set multiple values), so they give you the same benefit as many overloads on the constructor, without the need to have many overloads complicating the API for that class.



Related Topics



Leave a reply



Submit