Java Constructor - 2020
A constructor looks like a method except that it does not specify a return type. Its name must be exactly the name of the class that it constructs.
Actually, every class in Java has constructor. If no other constructor is specified, the Java compiler automatically creates a constructor with no arguments. If a constructor does not explicitly call superclass constructor, the compiler will automatically add an implicit call to the superclass no-arg constructor as the very first statement as we see the code below:
public class MyClass { public void out() { System.out.println("MyClass"); } // compiler will create this constructor if not defined public MyClass() { super(); } } public class DefaultConstructorTest { public static void main(String[] args) { MyClass mc = new MyClass(); mc.out(); } }
In the code below, because the MyClass class explicitly defines a constructor, Java compiler does not implicitly add a default. That means that trying to create a MyClass, with no arguments, will cause an error:
public class MyClass { public void out() { System.out.println("MyClass"); } public MyClass(int a) {} } public class DefaultConstructorTest { public static void main(String[] args) { MyClass mc = new MyClass(); // error: The constructor MyClass() is undefined MyClass mc2 = new MyClass(10); // OK mc.out(); } }
Before we investigate the order of initialization of a class which has constructor, static data, and not-static instance variable, let's briefly look at the constructor.
To create an object, we need three steps.
- Declare a reference variable
Make a new reference variable of a class or interface type. myCat is a Cat reference
Cat myCat = new Cat(); - Create an object
Cat myCat = new Cat();
- Link the object and the reference.
Assign the new object to the reference.
Cat myCat = new Cat();
When we use "new Cat();", we're not calling a method but a constructor.
It's the code that runs when we use new.
In other words, constructor is the code that runs when we instantiate an object.
Every class we create has a constructor, even if we don't write it ourselves.
Let's look at the following code and check what's happening when we do
Cat myCat = new Cat();
Complete code looks like this:
public class Cat extends Animal{ void makeSound() { System.out.println("Mew!"); } } public class Animal {} public class ConstructorTest { public static void main(String[] args) { Cat c = new Cat(); c.makeSound(); } }
Here are the things happening at runtime when the Cat constructor is invoked:
- Cat constructor is invoked. Every constructor invokes the constructor of its superclass with an implicit call to super().
- Animal, superclass of Cat, constructor is invoked.
- Object constructor invoked.
- Object instance variables are given their explicit values.
- Object constructor completes.
- Animal instance variables are given their values if any.
- Animal constructor completes.
- Cat instance variables are given their values if any.
- Cat constructor completes.
The order of initialization is determined by the order the appearance of the variable definition with a class.
In the following example, we'll find the order of initialization is:
- Instance variable
- Constructor
class Door { Door (int doorNum) { System.out.println("Door(" + doorNum + ")"); } } class Room { Room() { System.out.println("Room()"); d2 = new Door(22); } Door d1 = new Door(1); void floor() { System.out.println("floor()"); } Door d2 = new Door(2); } class InitOrder { public static void main (String[] args){ Room r = new Room(); r.floor(); } }
Output is:
Door(1) Door(2) Room() Door(22) floor()
When we instantiate the Room at:
Room r = new Room();
the code does not go into the constructor Room(). Instead it initializes the instance variable d1 and d2. To do that, it needs to make objects of type Door. Then, it assigns the new objects to the reference variables, d1 and d2. Then it goes to the constructor Room().
From the following example, we'll learn:
- Static initialization occurs only if it's necessary.
- Static objects are not reinitialized.
- The order of initialization is statics first, if they haven't already been initialized by a previous object creation, and then the non-static objects.
class StrangeDog { StrangeDog(){ System.out.println("Strange Dog()"); } static BabyDog sBaby3 = new BabyDog(3); } class NeighborDog { NeighborDog() { System.out.println("NeighborDog()"); } static BabyDog bDog = new BabyDog(1); } class BabyDog { BabyDog(int numBabyDog){ System.out.println("BabyDog(" + numBabyDog +")"); } } class Dog { BabyDog sBaby3 = new BabyDog(3); Dog (){ System.out.println("Dog() constructor"); } static BabyDog sBaby2= new BabyDog(2); } public class DogInit { public static void main (String[] args) { System.out.println("1: Creating Dog() in main()"); new Dog(); System.out.println("2: Creating Dog() in main()"); new Dog(); } static NeighborDog nbDog = new NeighborDog(); }
The output is:
BabyDog(1) NeighborDog() 1: Creating Dog() in main() BabyDog(2) BabyDog(3) Dog() constructor 2: Creating Dog() in main() BabyDog(3) Dog() constructor
To execute main() which is a static method, the DogInit class must be loaded, and its static fields nbDog is then initialized, which causes NeighborDog class to be loaded. Since the NeighborDog class contains static BabyDog object, BabyDog is then loaded. So, the BabyDog and NeighborDog classes get loaded before main() starts.
Then, in the main(), we load Dog class which has static field BabyDog sBaby2. After the static field it goes to regular field BabyDog sBaby3 and then construct Dog object. In the second creation of Dog from main(), it skips static sBaby2 and goes to sBaby3.
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization