0

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?

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
Mithra
  • 19
  • 5
  • Language-wise the default constructor has to be there for the language to make sense and compile correctly (if no other constructor has been provided). After all, you are writing `new Main()`, so there has to be a constructor `Main()` in the code, even if you did not write one. Also, its content is not empty, it implicitly calls the super constructor as well. `super();` (Object in this case). Also, the reflection API needs to have access to it as well (but thats an advanced topic). – Zabuzard Dec 09 '21 at 09:59
  • 1
    @Zabuzard technically, you don't need a constructor in a class. There is a weird case that I can't quite remember where the compiler creates synthetic classes that don't have constructors, not even the default one or a private one: they are entirely non-instantiable. – Andy Turner Dec 09 '21 at 10:01
  • `Main()` is not necessarily the 'default' constructor. The term 'default constructor' usually (as far as I know) refers to the constructor inserted by the compiler when you leave out explicit constructor in your source code. This is also referred to as *implicit constructor*. This is different from the no-args constructor, a constructor accepting zero arguments. A no-args constructor exists in two cases: when you define an explicit no-arg constructor, and when you define no constructor at all (in that case, the compiler generates one). – MC Emperor Dec 09 '21 at 10:10
  • @Zabuzard "I can't quite remember" [dredging from the distant past](https://stackoverflow.com/a/47883266/3788176). – Andy Turner Dec 09 '21 at 10:17
  • Yeah, I actually saw this back then and learned that the JVM supports non-constructable classes. But if you want to be able to write `new Main()`, you need a constructor in the bytecode, hence it has to be added (design-wise). Alternately they could have also decided to not have no-constructor support in the JVM and then interpret the absence of a constructor in the bytecode as the fact that a default constructor is present - then it wouldnt have to be added. But they didnt design it like that. Thats kinda my point of view on this question. – Zabuzard Dec 09 '21 at 10:22

4 Answers4

5

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.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • I might be wrong but I interpret OPs question more as a _"why is it useful to actually add the default constructor in the bytecode if it has no actual real logic attached to"_. Added an extra answer for that to complement yours. – Zabuzard Dec 09 '21 at 10:09
  • 1
    @Zabuzard I think I've already covered that: "Additionally..." – Andy Turner Dec 09 '21 at 10:09
  • @AndyTurner You have said that the constructor is used to create an instance of that class. Then what about 'new' keyword? Isn't it the one which does that work? – Mithra Dec 10 '21 at 12:52
  • No, I haven't said that: the constructor is used to initialize the instance of the class. The new class instance creation expression (which consists of qualifying instance (if any), the `new` keyword, class name, parentheses and parameters) causes an instance to be created and initialized; you can't really separate out any one bit of that. – Andy Turner Dec 10 '21 at 12:57
1

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, ...).

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
0

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

Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
0

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.

ActionON
  • 106
  • 1
  • 9