首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么没有调用我的子类构造函数?

为什么没有调用我的子类构造函数?
EN

Stack Overflow用户
提问于 2012-08-09 08:55:37
回答 3查看 957关注 0票数 0

我有这样的继承结构:

代码语言:javascript
复制
public abstract class Mom {
    int dummy;
    Mom() {
        dummy = 0;
    }
    Mom(int d) {
        this();
        dummy = d;
    }
}
public class Kid extends Mom {
    String foo;
    Kid() {
        super();
        foo = "";
    }
    Kid(int d) {
        super(d);
    }
}
// ...
Kid kiddo = new Kid(10);
// kiddo.foo == null !

我的论点-无构造函数的Kid从来没有被调用!以下是我所期望的:

  1. new Kid(10)Kid#Kid(int)
  2. super(d)Mom#Mom(int)
  3. this()Kid#Kid() // doh!
  4. super()Mom#Mom()

Mom那里可以调用Kid的无参数构造函数吗?

我想不是,我将添加一个抽象的method1 init()Mom将调用它,而Kid将不得不重写它。

但我只想知道确切的原因,如果可能的话,举例证明为什么要调用子类‘构造函数是个坏主意(即使子类的构造函数确实调用了super())。

代码语言:javascript
复制
// in Mom:
protected abstract void init();
public Mom() {
    dummy = 0;
    init();
}

// in Kid:
@Override
protected abstract void init() {
    foo = "";
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-08-09 09:21:57

来自JLS§8.8.7.1 (由我强调):

  • 替代构造函数调用以关键字this开始(可能以显式类型参数作为前缀)。它们用于调用同一类的备用构造函数.
  • 超类构造函数调用以关键字super (可能以显式类型参数作为前缀)或主表达式开始。它们用于调用直接超类的构造函数.

因此,这个构造函数调用总是引用同一个类,而不是一个子类。

虽然在构造函数中调用虚拟方法是可能的,但它是不安全的,并且被认为是错误的做法,因为它可能导致那些使用部分初始化的对象实例的方法。

对于您的问题,有几种可能的解决方案:

  1. 在声明时初始化成员foo,即foo = "";。这也被称为字段初始化器。
  2. 使用实例初始化器{ foo = ""; }。注意,如果需要,类中可以有多个实例初始化程序。
  3. 咬紧牙关,在所有构造函数中重复初始化。

根据JLS第12.5节,(1)和(2)中的初始化总是在调用构造函数之前执行,因此您有一个定义良好的对象初始化,而不需要求助于有问题的模式。

如果一个成员被多次初始化,那么最后一个初始化将获胜:

4)为该类执行实例初始化器和实例变量初始化器,将实例变量初始化器的值按从左到右的顺序分配给相应的实例变量,这些变量在类的源代码中以文本形式出现。

如果在构造函数中也初始化了相同的字段,则构造函数将获胜。

票数 2
EN

Stack Overflow用户

发布于 2012-08-09 08:58:37

我会安排这些,这样您就不需要调用每个构造函数了。

代码语言:javascript
复制
public abstract class Parent {
    final int dummy;

    Parent () {
        this(0);
    }
    Parent (int d) {
        dummy = d;
    }
}

public class Kid extends Parent {
    final String foo = "";

    Kid() {
    }

    Kid(int d) {
        super(d);
    }
}

使用final确保每个字段只设置一次。

从构造函数中调用任何可重写的方法被认为是错误的做法,因此使构造函数成为可重写的,这是个坏主意。

this()调用同一个类的构造函数,因为构造函数不遵循继承(静态方法也不)

代码语言:javascript
复制
new Kid(10) --> Kid#Kid(int)
super(d) --> Mom#Mom(int)
this() --> Mom#Mom()

构造函数会这样做,否则您将面临多次调用同一个构造函数的危险,并且无法保证只设置一次最终方法。

票数 6
EN

Stack Overflow用户

发布于 2012-08-09 09:01:25

您应该为Kid类拥有以下构造函数:

代码语言:javascript
复制
Kid(int i) {
  super(i);
  whatever();
}

Kid () {
  this( DEFAULT_VALUE);
}

因此,所有对父构造函数的调用都是通过子类的完全限定构造函数进行的。并为类的所有构造函数设置一个默认行为,这些构造函数不会被绕过,就像当前代码的情况一样。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11879865

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档