Object Construction & Destruction in Java

constructoroverloading

In the previous blog we learned about static fields, methods, constants, etc. If you want to learn more about it, visit the blog Static Methods and Variables in Java. In this blog, we will go through object construction and destruction. In the previous blog, we discussed how we can define a constructor and create an object using it. As Object Construction plays a vital role, Java provides a number of ways for writing the constructors.

Constructor Overloading and Method Overloading

Just like OOP, Java also supports overloading. Overloading is when the write more than one constructor or method having the same names for constructors and methods but differ in the return type and no of parameters is called overloading. When there is more than one constructor with the same name but differs in no. of parameters and type of parameters is called constructor overloading. While overloading constructors, the constructors must have different types of parameters and different numbers of parameters, because if we use the same signature for the constructors, the constructor will be confused about which constructor to use and will throw an error. So it is mandatory to give different types of parameters or different no. of parameters to the constructor.

e.g.

public DevOverloadingConstructorEx();
public DevOverloadingConstructorEx(int atrowelValue,double atrowelValue2);
............;

In the above example there are two constructors with the same name but having different parameters. The first constructor has 0 parameters and the second constructor has 2 parameters.

e.g.

public class DevOverloadingConstructorEx {
  public DevOverloadingConstructorEx(){
    System.out.println("You are inside the default constructor.");
  }

  public DevOverloadingConstructorEx(int atrowelValue){
    System.out.println("You are inside the constructor with one parameter.");
    int value = atrowelValue;
    System.out.println("The value of the variable is:- "+value);
  }

  public DevOverloadingConstructorEx(int atrowelValue, int atrowelValue2){
    System.out.println("You are inside the constructor with two parameters.");
    int value = atrowelValue+atrowelValue2;
    System.out.println("The addition of the variables is:- "+value);
  }

  public DevOverloadingConstructorEx(int atrowelValue, int atrowelValue2, double atrowelValue3){
    System.out.println("You are inside the constructor with three   parameters.");
    double value = atrowelValue+atrowelValue2+atrowelValue3;
    System.out.println("The addition of the variables is:- "+value);
  }

  public static void main(String[] args) {
    DevOverloadingConstructorEx atrowelObj  = new DevOverloadingConstructorEx();
    DevOverloadingConstructorEx atrowelObj1 = new DevOverloadingConstructorEx(10);
    DevOverloadingConstructorEx atrowelObj2 = new DevOverloadingConstructorEx(10,20);
    DevOverloadingConstructorEx atrowelObj3 = new DevOverloadingConstructorEx(10,20,90.35);
  }
}

Output:

You are inside the default constructor.
You are inside the constructor with one parameter.
The value of the variable is :- 10
You are inside the constructor with two parameters.
The addition of the variables is :- 30
You are inside the constructor with three parameters.
The addition of the variables is :- 120.35

Method Overloading follows the same concept as Constructor Overloading, only the difference is it overloads the method. When one or more methods having the same name with different datatypes of parameters and different no. of parameters is called Method Overloading. Methods can be overloaded by using two ways.

  1. By changing the no of arguments -

    e.g.

    public void displayAtrowelValue(int atrowelValue){
    ...........;
    }
    
    public void displayAtrowelValue(int atrowelValue, int atrowelValue2){
    ...........;
    }
    
    public void displayAtrowelValue(int atrowelValue, int atrowelValue2, int atrowelValue3){
    .....................;
    }
  2. By changing the datatype of arguments -

    e.g.

    public void displayAtrowelValue(int atrowelValue){
    ...........;
    }
    
    public void displayAtrowelValue(int atrowelValue, int atrowelValue2){
    ...........;
    }
    
    public void displayAtrowelValue(int atrowelValue, int atrowelValue2, double atrowelValue3){
    .....................;
    }

    It is mandatory to use one the two ways for overloading the method. Because if we use the same signature for the methods then the compiler will get confused which method to execute and will throw an error.

    e.g.

    public class MyClass {
    
      public void displayVaueOfOverloadedMethod() {
        System.out.println("You are inside the with no parameters.");
      }
    
      public void displayVaueOfOverloadedMethod(int atrowelValue) {
        System.out.println("You are inside the method with one parameter.");
        int value = atrowelValue;
        System.out.println("The value of the variable is :- "+value);
      }
    
      public void displayVaueOfOverloadedMethod(int atrowelValue, int atrowelValue2) {
        System.out.println("You are inside the method with two parameters.");
        int value = atrowelValue+atrowelValue2;
        System.out.println("The addition of the variables is :- "+value);
      }
    
      public void displayVaueOfOverloadedMethod(int atrowelValue, int atrowelValue2, double atrowelValue3) {
        System.out.println("You are inside the method with three parameters.");
        double value = atrowelValue+atrowelValue2+atrowelValue3;
        System.out.println("The addition of the variables is :- "+value);
      }
    
      public static void main(String[] args) {
        MyClass atrowelObj = new MyClass();
        atrowelObj.displayVaueOfOverloadedMethod(10);
        atrowelObj.displayVaueOfOverloadedMethod(10,20);
        atrowelObj.displayVaueOfOverloadedMethod(10,20,94.23);
      }
     }

    Output

    You are inside the method with one parameter.
    The value of the variable is :- 10
    You are inside the method with two parameters.
    The addition of the variables is :- 30
    You are inside the method with three parameters.
    The addition of the variables is :- 124.23

Field Initialization with default values

If the fields in the constructor are not set explicitly with the values, then the fields are set automatically with the values as: for numbers it is set as 0, for boolean it is set to false and for reference of object it is set to null. It is not good practice to rely on the default values because sometimes it becomes harder for programmers to understand the code if the values are set to default.

For example, if we consider the example Student which has the fields like name, age, and address. Now suppose if we don’t specify the value and the value will be set to the default as the name will have the value as null, age will have 0, and address will also have a value as null. This is not good practice, because if the coder calls getName() or getAddress() then they will get the values as null which were not expected.


Default Constructors

As we have seen in our previous blogs, we have created a default constructor for creating the object of the class. If there are no constructors used in the class, then the default constructor is called implicitly during object creation. The default constructor sets instance fields to the default values like for a number it is set to 0, for a boolean it sets false as the default value, for objects it sets the value as null, etc.

e.g.

public AtrowelStudent() {
  atrowelName = "Atrowel";
  atrowelValue = 23;
}

If a class has a constructor and if it doesn’t have default constructor, then the compiler will throw an error because we cannot create an object with the constructors other than default constructor.

e.g.

public AtrowelStudent(String name, int age, String address) {
.............;
}
AtrowelStudent atrowelStudent = new AtrowelStudent();

If we consider the above example then it will throw an error because the default constructor is not created, we only have a constructor with 3 arguments. We cannot use this constructor for creating an object. So it's mandatory to have a default constructor when we define any constructor. Note that we can avoid writing the default constructor only when we don’t have any other constructor. But if the class has even a single constructor then it is mandatory to have the default constructor for creating an instance.


Explicit Field Initialization in Java

By overloading the constructor methods in the call, we can construct many ways to set the initial state of the instance fields in the class. It is a good practice to set the instance fields of the class to meaningful values without caring of the constructor call. In the class definition, we can assign any values to the instance fields.

e.g.

class AtrowelStudent{
  private String atrowelName = "";
}

In the above example the assignment is done before the constructor starts its execution. The values initialized to the instance fields are not constant values. E can even initialize the instance fields with the method call.

e.g.

class AtrowelStudent{

  private static int atrowelStaticId;
  private int atrowelId = assignAtrowelId() ;

  public static int assignAtrowelId() {
    int atrowelValue = atrowelStaticId;
    atrowelStaticId++;
    return atrowelValue;
  }
}

Now here in the example, we have a method assignAtrowelId() in which we have assigned the value of static field i.e. atrowelStaticId to the new variable i.e.atrowelValue and this atrowelValue is returned to the method assignAtrowelId(), which is assigned to the atrowelId with the help of method call.


Best Practices for Parameter Names

When defining a constructor many times developers give the names to the parameters that are meaningless, due to which it becomes a frustrating job for any other developer because meaningless names lead him to go through the entire code for understanding what the parameters name does.

e.g.

public AtrowelStudent(String a, String b) {
  atrowelName = a;
  atroweAddress = b;
}

In the given example we have defined a constructor with two parameters a and b. Now look at this line we will not understand what the parameter a is used for and what b is used for. For knowing it we have to see the code which is written inside the constructor, so now here we will understand that a is used for name and b is used for address.

In large applications if we give the parameters names that are not meaningful, then the developer will have to read the code, which will waste his time. So this is the drawback of not using the meaningful names to the parameters. In order to eliminate this issue we should follow the best practice of giving meaningful names to the parameters when defined in the constructor. Some developers follow the practice of giving the name to the parameter that describes its functionality.

e.g.

public AtrowelStudent(String name, String address) {
	atrowelName = name;
	atrowelAddress = address;
}

Now in this example we can easily figure out just by seeing the definition, the purpose of the parameter name. Another common practice is to use the same name for the parameters that we use for instance fields. For example, if we will call the parameter atrowelName, then the atrowelName will refer to the parameter and not the instance field. But if we want to access the instance fields then we can do it by using “this” keyword. We will learn “this” keyword in our upcoming blogs.

e.g.

public AtrowelStudent(String atrowelName, String atrwoelAddress) {
	this.atrowelName = atrowelName;
	this atrowelAddress = atrowelAddress;
}

Calling Constructor inside the Constructor

There can be some situations where developers want to call the constructor inside the constructor, then we use this keyword. this keyword refers to the implicit parameters of the method. This keyword has other uses too. For example, if the constructor has the form this(......), then the constructor calls the other constructor that has the same name. For example:

e.g.

public AtrowelStudent(int values) {
	this(AtrowelStudent+ atrowelName, atrowelAge);//calling AtrowelStudent(String, int)

}

Now here when the constructor AtrowelStudent(20) will be called, then AtrowelStudent(int) will call the other constructor i.e. AtrowelStudent(String, int)


Initialization Blocks

We have seen two ways of initializing the data fields

  1. Assigning a value during the declaration.
  2. Setting a value in the constructor.

Java supports one more mechanism which is Initialization Block. A class declaration may contain an arbitrary block of code. These blocks are executed when the object of the class is created.

e.g.

class AtrowelStudent{
  private static int atrowelNextId;
  private int atrowelId;
  private String atrowelName;

  private double atrowelSalary;{
    private int atrowelId;
    atrowelId = atrowelNextId;
    atrowelNextId++;
  }

  public Employee(String name, double salary){
    atrowelName = name;
    atrowelSalary = salary;
  }

  public Employee(){
    atrowelName = "";
    atrowelSalary = 0;
  }
  . . .
}

In the above example atrowelId is initialized in the object initialization block, regardless of which constructor will be used for creating the object. The initialization block runs first and then the constructor is executed. This mechanism is not mandatory and not common.

Using no of ways for initializing the data fields, makes it quite confusing for the construction process. Now we will see what happens when the constructor is called.

  1. If the constructor has another constructor inside it, then the constructor calls the inner constructor and that inner constructor gets executed with the provided arguments.
  2. Else,
    • The data fields that are defined in the class are initialized to default values i.e. 0 if it is a number, null if object or false if boolean.
    • All the initialization blocks and field initializers that are used in the class are executed in the sequential order i.e. the order in which they occur in the class declaration.
    • Execution of the body of constructor

It is always a best practice to organize the initialization code in a manner so that the programmer can easily understand it without having a deep knowledge of the language. In order to initialize the static fields we can either use the static block or can provide an initial value.

e.g.

private static int nexatrowelId = 1;

Suppose if the static field has the complex initialization code then we can use a static initialization block. To define it in the static block we must use the static keyword at the beginning of the block.

e.g.

static{
  var atrowelValueGenerator = new Random();
  atrowelId = atrowelValueGenerator.nextInt(10000);
}

As the static initialization occurs when the class is first loaded, the value of static fields and instance fields is 0 if the value is in the number, false if it is boolean and null if it is an object. The static fields and instance fields can have other values only when they are set explicitly.s

e.g.

import java.util.*;
public class AtrowelConstructorTest {
	public static void main(String[] args) {
      var atrowelOjbect = new AtrowelStudent[3];
      atrowelOjbect[0] = new AtrowelStudent("Jackson", "London");
      atrowelOjbect[1] = new AtrowelStudent("Canada");
      atrowelOjbect[2] = new AtrowelStudent();

      for (AtrowelStudent e : atrowelOjbect)
        System.out.println("name=" + e.getAtrowelName() +"
"+  "address=" + e.getAtrowelAddress());
	}
}

class AtrowelStudent{
	private static int atrowelNextId;
	private int atrowelId;
	private String atrowelName = ""; // instance field initialization
	private String atrowelAddress="";

    // static initialization block
	static{
      var atrowelGenerator = new Random();
      satrowelNextId = atrowelGenerator.nextInt(10000);
	}

    // object initialization block
	{
      atrowelId = atrowelNextId;
      atrowelNextId++;
	}

    // three overloaded constructors
	public AtrowelStudent(String aName, String aAddress) {
      atrowelName = aName;
      atrowelAddress = aAddress;
	}

    public AtrowelStudent(String address) {
    // calls the AtrowelStudent(String,String) constructor
    this("AtrowelStudent #" + atrowelNextId, address);
	}

    // the default constructor
	public AtrowelStudent() {

	}

    public String getAtrowelName() {
      return atrowelName;
	}

    public String getAtrowelAddress() {
      return atrowelAddress;
	}

    public int getAtrowelId() {
      return atrowelId;
	}
}

Object Destruction and finalize()

Many times there occurs a situation where the object is no longer needed. In order to remove it or clean up the code, destructor methods are used in C++. Since Java supports garbage collection, manual memory reclamation is not needed, so Java doesn’t support destructors. Many times there may be a situation where an object will use resources other than memory. In this case, it becomes important that the resource be reclaimed and recycled when it is no longer needed. We can use the close() method in order to do the cleanup whenever we have finished using the resource. We can call the close() method whenever we are one with the object.

Note: do not use the finalize() method for cleanup purposes. The purpose of this method was to be called before the garbage collector cleans away an object. But the drawback is we don’t know when this method will get called, so this method is deprecated.

Get in Touch

Atrowel will be pleased to receive your feedback and suggestions. Those of you who would like to contribute, please send us an email.