Home > Software design >  Actual use of default constructor in java
Actual use of default constructor in java

Time:12-09

Default constructors are provided by the compiler when the programmer fails to write any constructor to a class. And it is said that these constucors are used to initialize default values to the class attributes.However if the programmer provides a constructor, be it simple one like:

public class Main {
  int a;

  Main() { // user defined simple constructor
    System.out.println("hello");
  }

  public static main(String[] args) {
    Main obj = new Main();
  }
}

In the above code the user has included a constructor. However it doesnot initialize the instance variable(a). Moreover default constructor won't be called. Then how come the variable 'a' gets initialized to it's default value.

If it is like, the default constructors do not initialize the class variables to their default values and compiler does it automatically, then what is the actual use of default constructor?

Why does the compiler add a default constructor in the case when the user fails to write a constructor?

CodePudding user response:

Then how come the variable 'a' gets initialized to it's default value.

Because the language specifies that fields are initialized to their default values. Specifically, JLS 4.12.5:

Every variable in a program must have a value before its value is used:

  • Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):
    • ...
    • For type int, the default value is zero, that is, 0.
      • ...

Even if you did initialize it in the constructor, you could read the field beforehand, and observe its default value. For example:

  Main() { // user defined simple constructor
    System.out.println(a);  // Prints 0
    a = 1;
  }

Although it is mostly hidden from you in Java, new Main() does two separate things (see JLS 15.9.4 for more detail, as it's actually more than two things):

  • It creates an instance of Main
  • Then it invokes the constructor in order to initialize that instance.

The initialization of the fields to their default values actually occurs when the instance is created (the first step, as described in the quote from JLS above); so, even if the second step of invoking a constructor didn't happen, the fields are still initialized to their default values.

Why does the compiler add a default constructor in the case when the user fails to write a constructor?

Because otherwise you wouldn't be able to create an instance of that class.

Additionally, the default constructor (like all constructors which don't call this(...) on their first line) invokes the super constructor. So, it would look something like:

Main() {
  super();
}

You have to call the super constructor of a class in order to do the necessary initialization of the base class.

CodePudding user response:

Default values

And it is said that these constucors are used to initialize default values to the class attributes.

That is incorrect. The constructors (including the default no-arg constructor) does not initialize the fields to their default values. This is done implicitly beforehand by the language already (see the JLS definition).

The default constructor is identical to a completely empty constructor:

Foo() {}

Technically, like other constructors, this implicitly still contains the call to the parent class constructor:

Foo() {
  super();
}

Also have a look at the bytecode of public class Foo {}, which is:

public class Foo {
  public Foo();
    Code:
       0: aload_0       
       1: invokespecial #1  // Method java/lang/Object."<init>":()V
       4: return        
}

You can clearly see the default constructor with code to invoke Objects constructor.


Why add it in bytecode?

Why does the compiler add a default constructor in the case when the user fails to write a constructor?

In theory it would not have to do that. However, language-design wise it is much easier to just add it to simplify the rest of the language.

For example, then you do not need any magic to make new Foo(); work, since the constructor just actually exists in the code that the JVM executes.

Same holds for more advanced topics such as the reflection API, which has methods like

Object foo = Foo.class.getConstructor().newInstance();

So if the constructor just actually exists in the bytecode, again, you do not need any magic in the JVM to make this work. It just works out of the box.

At the end of the day it was a design decision by the developers to create it in the way they did. They could have realized it differently as well.

That way however, you have a much clearer split between Java and JVM bytecode as languages. And technically you can also create classes in bytecode that do not even have constructors at all (which you can not create from within Java), which is interesting to special tools and other languages that compile to JVM bytecode (Kotlin, Groovy, Scala, Clojure, ...).

CodePudding user response:

Fields are initialised with defaut values (0, 0.0, null, false, etc...)

CodePudding user response:

Default behavior is useful. The alternative may be deleting it if it isn't being used or putting it in another class, or setting it as null. Most of the time though, you do want default behavior. And that is the general idea, I believe.

  • Related