Daniel
Daniel

Reputation: 311

Java subclass constructors not calling parent class constructor

I ran into a weird situation the other day. Here it is:

I had an abstract class and a child class extending it. The abstract class had a no parameter constructor to initialize a map, but that's it.

The sub-class didn't have any constructors that I explicitly wrote, and everything worked fine.

Then one day I added a custom constructor in the subclass with a bunch of parameters for a unit test. This broke my main program, however, because the map in its parent class was always null.

To solve it, I put another constructor in the subclass that was totally blank (no params or anything). This for some reason assured that the super class constructor would be called and no null pointer exception thrown. Why was that not getting called before and why is it working now?

Subclass:

public class BillToSite extends XWStoreRequestDataElement {
private String country;
private String state;
private String county;
private String city;
private String zip;
private String address;

public BillToSite() { } //WHY DOES THIS FIX IT???

//Only used for unit test. 
public BillToSite(String address, String city, String state, String zip, String county, String country){
    this.address = address;
    this.city = city;
    this.state = state;
    this.zip = zip;
    this.county = county;
    this.country = country;
}

Abstract class:

public abstract class XWStoreRequestDataElement {
private Map<String, String> attributes;

public XWStoreRequestDataElement(){
    attributes = new HashMap<>();
}

Upvotes: 1

Views: 2652

Answers (3)

Ralf Kleberhoff
Ralf Kleberhoff

Reputation: 7290

I cannot explain why you experience BillToSite instances with attributes=null. That contradicts the way Java works. But I can explain why you have to write the no-args constructor.

Necessity of explicit no-args constructor

I suppose that in your program BillToSite instances are created using new BillToSite(), either explicitly or by some framework... (otherwise the class wouldn't have any instances).

In the original BillToSite.java you had no explicit constructor, so the Java compiler created one for you, effectively identical to the one you asked about.

Introducing the 6-args constructor deactivated the compiler's auto-creation of the no-args constructor, and as your code relies on this constructor, it's clear to me that it couldn't work any longer. Normally, you should have got compile errors for the new BillToSite() calls. If you didn't get them, I'd guess that the instance creation happens in some hidden place using reflection.

So, when you wrote the explicit no-args constructor, you re-introduced the missing element that was no longer auto-generated.

Calling the super constructor

You never need to explicitly begin a constructor with super() (we may regard it bad style if you omit it, thus not making clear which superclass constructor is to be used). If you don't explicitly call a super(...) or this(...) constructor, the compiler effectively inserts super() at the very beginning. In this regard, some of the other answers are misleading.

So adding that line to your BillToSite(...) constructors can't change anything.

I'd recommend that you run your program under debugger control with a breakpoint on the BillToSite() constructor and watch the attributes field. I'm sure it will be initialized to an empty HashSet. If you later experience a null value, the problem must be in another part of your code.

Upvotes: 3

sbansal
sbansal

Reputation: 34

By default, Java provides a no-args constructor that makes a call to super() for any class that doesn't have any explicitly defined constructors. However, when you explicitly define a constructor, Java doesn't do that so you have to call super() yourself.

So, when you didn't have that subclass constructor, Java handled the no-args constructor for you, but when you added that subclass constructor, Java stopped handling that so you had to do it yourself. Another solution would to just explicitly call super() in your original subclass constructor instead of having a separate no-args constructor for it since all you really need to do is call super() to initialize the map.

Upvotes: 0

doominabox1
doominabox1

Reputation: 458

Simply call super(); in public BillToSite(){} For example:

public BillToSite(String address, String city, String state, String zip, String county, String country){
    super();
    this.address = address;
    this.city = city;
    this.state = state;
    this.zip = zip;
    this.county = county;
    this.country = country;
}

Upvotes: 0

Related Questions