1

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<>();
}

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

That makes sense why you should always make your own constructors. I'm using Spring, so I know a lot of things are taken care of for me under the surface. I still think this behavior doesn't make sense at all for Java, but I know the better practices now.
Hey, I deleted my answer because you explained this a lot better than I did.
0

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;
}

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.