Tuesday, September 7, 2021

Why Default or No Argument Constructor is Important in Java Class? Answer

Almost all Java developers know that compiler adds a default constructor or better known as a no-argument constructor in every Java class, but many of them forget that it only does when you don't provide any other constructor. This means it becomes the developers' responsibility to add a no-argument constructor if he is adding an explicit constructor. Now, Why it's important to provide a default constructor in Java, What happens if your class doesn't have a no-argument constructor? Well, this is how it's asked in many Java interviews, most commonly as part of Spring and Hibernate interviews.

It's not mandatory to define default constructor, but if you are writing Hibernate persistent class, JPA entities, or using the Spring framework to manage object creation and wiring dependencies, you need to be a bit careful. Many of open source framework, uses reflection to create instance or Object at runtime, based upon the name of the class.

For example, When Hibernate creates an instance of entities using reflection it uses the Class.newInstance() method, which requires a no-argument constructor to create an instance. It's effectively equivalent to the new Entity().

This method throws InstantiationException if it doesn't found any no-argument constructor in the Entity class, and that's why it's advised to provide a no-argument constructor.

Btw, if you are new to the world of Hibernate then I also suggest you go through a hands-on course like these best Hibernate and JPA courses for Java developers. It's a great resource to understand the Hibernate fundamentals and advanced concepts for beginners and experienced java developers. 


Effect of not defining Default Constructor in Java

By the way, it's not just Hibernate, who makes use of Reflection to create an instance of the class. If you are familiar with Spring and Dependency Injection, that you might know that Spring also creates an instance of a class using reflection, but it's more sophisticated and allow you to choose which constructor to call by specifying various constructor argument using <constructor-arg value="someValue"/> and <constructor-arg ref="someRefrence"/> tags.



How about this code, do you think this will work if Order class doesn't have a no argument constructor?

<bean id="OrderManager" class="com.exchange.OrderManager">
           <property name="symbolValidator" ref="someSymbolValidator"/>
</bean>

No, it will not work if your OrderManager class has an explicit constructor, because the above configuration will create an instance of OrderManager by calling no argument constructor and then use Setter Injection to provided dependency. If you have defined your class like below, then you better use constructor injection to create an instance of this bean.

Why Provide No Argument Constructor in a Java class

public class OrderManager{
    private SymbolValidator symbolValidator;

    public OrderManager(SymbolValidator validator){
         symbolValidator = validator;
    }

    .....

}


The above configuration will show the following error :

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'OrderManager' defined in class path resource [app-config.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.exchange.OrderManager]: No default constructor found;

So, You should always define a no argument constructor in your Java class, even if you are writing an explicit constructor, until you are absolutely sure that, it's won't be instantiated using reflection and instantiating it with no argument constructor is a bug, like in our example of Spring Bean management. 

Though, In the case of Hibernate Persistent classes or Entities, it's must to provide a no argument constructor, so that Hibernate can create instance of Persistence classes, when you hibernate load them from database. It also uses newInstance() method to create instance of persistent classes.


6 comments:

  1. How we know, java.lang package is default ?

    ReplyDelete
  2. Using an IDE like Eclipse points out to such issues even before you compile the code. So if you create that parametrized constructor and forget the default constructor, there's Eclipse to come to your rescue!

    ReplyDelete
  3. You might like to make a comment about Unsafe.allocateInstance(Class) which doesn't call a constructor.

    ReplyDelete
  4. Recently I missed no-argument constructor for a class, which was not final but doesn't implement an interface and don't have a default constructor, because of another parameteric constructor present in the class. Now you can't create mock or dummy version of that class, because
    a) it doesn't implement an interface
    b) there is no default constructor, means you can't extend it until you use their parametric constructor, which is not possible in case of dummy implementation. This makes testing that class a lot difficult. This teaches me lesson that implement interface and provide no arg constructor alteast.

    ReplyDelete
  5. No-argument constructor are evil, it's been promoted by Sun on various stage e.g. in Servlet, Reflection and other places, which leads to brittle and hard to test code. With no argument constructor dependencies are hidden, you don't know what a class need to get it's job done, and you only find it after facing problem. Since there is no class, which can work without being independent on other class, call it collaborators, as professional coder, it's your job to make them obvious. When I look a class, I first see it's constructor, that give me enough idea, what I need to use this class, with this no argument constructor mess, you lose that visibility.

    ReplyDelete
  6. You should never write a class with a no argument constructor unless you absolutely must.

    That implies the object is mutable, and that its dependencies are set on setters.

    That is an anti pattern (though, all too common).

    Make classes immutable, use the constructor injection pattern, and your code will be more maintainable, debuggable,

    No this does not make it hard to test -- provide the requirements on the constructor (use injection if desired). This is FAR more testable than anything with a no-arg constructor that is mutable.

    In short, I agree with the "No-argument constructors are evil" side. I violently agree. I used to be in the other camp, long ago, but have seen the errors in my ways. Making your dependencies explicit, and making things immutable, leads to code that is much easier to debug and test. And radically easier to refactor and maintain.

    ReplyDelete