【问题标题】:Java subclass constructors not calling parent class constructorJava子类构造函数不调用父类构造函数
【发布时间】:2018-02-28 15:25:10
【问题描述】:

前几天我遇到了一个奇怪的情况。这里是:

我有一个抽象类和一个扩展它的子类。抽象类有一个无参数构造函数来初始化地图,但就是这样。

子类没有我明确编写的任何构造函数,一切正常。

然后有一天,我在子类中添加了一个自定义构造函数,其中包含一组用于单元测试的参数。然而,这破坏了我的主程序,因为其父类中的地图始终为空。

为了解决这个问题,我在完全空白的子类中放置了另一个构造函数(没有参数或任何东西)。出于某种原因,这确保了超类构造函数将被调用并且不会抛出空指针异常。为什么之前没有被调用,为什么现在可以工作?

子类:

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

抽象类:

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

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

【问题讨论】:

    标签: java inheritance constructor


    【解决方案1】:

    我无法解释为什么您会遇到BillToSite 实例与attributes=null。这与 Java 的工作方式相矛盾。但我可以解释为什么你必须编写无参数构造函数。

    显式无参数构造函数的必要性

    我想在您的程序中BillToSite 实例是使用new BillToSite() 创建的,无论是显式还是由某个框架...(否则该类将没有任何实例)。

    在最初的 BillToSite.java 中,您没有显式构造函数,因此 Java 编译器为您创建了一个,实际上与您询问的那个相同。

    引入 6-args 构造函数禁用了编译器自动创建的无参数构造函数,并且由于您的代码依赖于这个构造函数,我很清楚它不能再工作了。通常,您应该遇到new BillToSite() 调用的编译错误。如果你没有得到它们,我猜想实例创建发生在使用反射的某个隐藏位置。

    因此,当您编写显式无参数构造函数时,您重新引入了不再自动生成的缺失元素。

    调用超级构造函数

    你永远不需要显式地以super() 开始构造函数(如果你省略它,我们可能会认为它的风格不好,因此不清楚要使用哪个超类构造函数)。如果您没有显式调用super(...)this(...) 构造函数,编译器会在开头有效地插入super()。在这方面,其他一些答案具有误导性。

    因此,将该行添加到您的 BillToSite(...) 构造函数不会改变任何内容。

    我建议您在调试器控制下运行您的程序,并在 BillToSite() 构造函数上设置断点并观察 attributes 字段。我确信它将被初始化为一个空的HashSet。如果您以后遇到空值,则问题一定出在代码的另一部分。

    【讨论】:

    • 这是有道理的,为什么您应该始终创建自己的构造函数。我正在使用 Spring,所以我知道很多事情都在表面下为我处理好了。我仍然认为这种行为对 Java 来说根本没有意义,但我现在知道更好的做法。
    • 嘿,我删除了我的答案,因为您对此的解释比我做得好。
    【解决方案2】:

    默认情况下,Java 提供了一个无参数构造函数,该构造函数对没有任何明确定义的构造函数的任何类调用 super()。但是,当您显式定义构造函数时,Java 不会这样做,因此您必须自己调用 super()

    因此,当您没有该子类构造函数时,Java 会为您处理无参数构造函数,但当您添加该子类构造函数时,Java 会停止处理,因此您必须自己处理。另一种解决方案是在原始子类构造函数中显式调用super(),而不是为其使用单独的无参数构造函数,因为您真正需要做的就是调用super() 来初始化地图。

    【讨论】:

      【解决方案3】:

      只需在public BillToSite(){} 中调用super(); 例如:

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

      【讨论】:

        猜你喜欢
        • 2021-05-08
        • 1970-01-01
        • 1970-01-01
        • 2018-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多