[java] Constructor overloading in Java - best practice

There are a few topics similar to this, but I couldn't find one with a sufficient answer.

I would like to know what is the best practice for constructor overloading in Java. I already have my own thoughts on the subject, but I'd like to hear more advice.

I'm referring to both constructor overloading in a simple class and constructor overloading while inheriting an already overloaded class (meaning the base class has overloaded constructors).

Thanks :)

This question is related to java constructor overloading constructor-overloading

The answer is


Constructor overloading is like method overloading. Constructors can be overloaded to create objects in different ways.

The compiler differentiates constructors based on how many arguments are present in the constructor and other parameters like the order in which the arguments are passed.

For further details about java constructor, please visit https://tecloger.com/constructor-in-java/


I think the best practice is to have single primary constructor to which the overloaded constructors refer to by calling this() with the relevant parameter defaults. The reason for this is that it makes it much clearer what is the constructed state of the object is - really you can think of the primary constructor as the only real constructor, the others just delegate to it

One example of this might be JTable - the primary constructor takes a TableModel (plus column and selection models) and the other constructors call this primary constructor.

For subclasses where the superclass already has overloaded constructors, I would tend to assume that it is reasonable to treat any of the parent class's constructors as primary and think it is perfectly legitimate not to have a single primary constructor. For example,when extending Exception, I often provide 3 constructors, one taking just a String message, one taking a Throwable cause and the other taking both. Each of these constructors calls super directly.


While there are no "official guidelines" I follow the principle of KISS and DRY. Make the overloaded constructors as simple as possible, and the simplest way is that they only call this(...). That way you only need to check and handle the parameters once and only once.

public class Simple {

    public Simple() {
        this(null);
    }

    public Simple(Resource r) {
        this(r, null);
    }

    public Simple(Resource r1, Resource r2) {
        // Guard statements, initialize resources or throw exceptions if
        // the resources are wrong
        if (r1 == null) {
            r1 = new Resource();
        }
        if (r2 == null) {
            r2 = new Resource();
        }

        // do whatever with resources
    }

}

From a unit testing standpoint, it'll become easy to test the class since you can put in the resources into it. If the class has many resources (or collaborators as some OO-geeks call it), consider one of these two things:

Make a parameter class

public class SimpleParams {
    Resource r1;
    Resource r2;
    // Imagine there are setters and getters here but I'm too lazy 
    // to write it out. you can make it the parameter class 
    // "immutable" if you don't have setters and only set the 
    // resources through the SimpleParams constructor
}

The constructor in Simple only either needs to split the SimpleParams parameter:

public Simple(SimpleParams params) {
    this(params.getR1(), params.getR2());
}

…or make SimpleParams an attribute:

public Simple(Resource r1, Resource r2) {
    this(new SimpleParams(r1, r2));
}

public Simple(SimpleParams params) {
    this.params = params;
}

Make a factory class

Make a factory class that initializes the resources for you, which is favorable if initializing the resources is a bit difficult:

public interface ResourceFactory {
    public Resource createR1();
    public Resource createR2();
}

The constructor is then done in the same manner as with the parameter class:

public Simple(ResourceFactory factory) {
    this(factory.createR1(), factory.createR2());
} 

Make a combination of both

Yeah... you can mix and match both ways depending on what is easier for you at the time. Parameter classes and simple factory classes are pretty much the same thing considering the Simple class that they're used the same way.


Well, here's an example for overloaded constructors.

public class Employee
{
   private String name;
   private int age;

   public Employee()
   {
      System.out.println("We are inside Employee() constructor");
   }

   public Employee(String name)
   {
      System.out.println("We are inside Employee(String name) constructor");
      this.name = name;
   }

   public Employee(String name, int age)
   {
      System.out.println("We are inside Employee(String name, int age) constructor");
      this.name = name;
      this.age = age;
   }

   public Employee(int age)
   {
      System.out.println("We are inside Employee(int age) constructor");
      this.age = age; 
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }

   public int getAge()
   {
      return age;
   }

   public void setAge(int age)
   {
      this.age = age;
   }
}

In the above example you can see overloaded constructors. Name of the constructors is same but each constructors has different parameters.

Here are some resources which throw more light on constructor overloading in java,

Constructors.

Constructor explanation.


It really depends on the kind of classes as not all classes are created equal.

As general guideline I would suggest 2 options:

  • For value & immutable classes (Exception, Integer, DTOs and such) use single primary constructor as suggested in above answer
  • For everything else (session beans, services, mutable objects, JPA & JAXB entities and so on) use default constructor only with sensible defaults on all the properties so it can be used without additional configuration

If you have a very complex class with a lot of options of which only some combinations are valid, consider using a Builder. Works very well both codewise but also logically.

The Builder is a nested class with methods only designed to set fields, and then the ComplexClass constructor only takes such a Builder as an argument.


Edit: The ComplexClass constructor can ensure that the state in the Builder is valid. This is very hard to do if you just use setters on ComplexClass.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to constructor

Two constructors Class constructor type in typescript? ReactJS: Warning: setState(...): Cannot update during an existing state transition Inheritance with base class constructor with parameters What is the difference between using constructor vs getInitialState in React / React Native? Getting error: ISO C++ forbids declaration of with no type undefined reference to 'vtable for class' constructor Call asynchronous method in constructor? Purpose of a constructor in Java? __init__() missing 1 required positional argument

Examples related to overloading

What is the difference between dynamic and static polymorphism in Java? TypeScript function overloading Constructor overload in TypeScript What is the difference between method overloading and overriding? Differentiate between function overloading and function overriding How do I use method overloading in Python? How can I create a Java method that accepts a variable number of arguments? Python function overloading PHP function overloading What is function overloading and overriding in php?

Examples related to constructor-overloading

C# constructors overloading Constructor overloading in Java - best practice