Reputation: 311
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
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.
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.
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
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
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