我想知道为什么在java构造函数是不继承的?你知道当你上这样的课时:

public class Super {

  public Super(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    this.serviceA = serviceA;
    //etc
  } 

}

以后当你从Super继承时,java会抱怨没有定义默认构造函数。解决方案显然是这样的:

public class Son extends Super{

  public Son(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    super(serviceA,serviceB,serviceC);
  }

}

这段代码是重复的,不是DRY和无用的(恕我直言)…这又带来了一个问题:

为什么java不支持构造函数继承?不允许这种继承有什么好处吗?


当前回答

因为构造函数是一个实现细节——它们不是接口/超类的用户实际上可以调用的东西。当他们得到一个实例时,它已经被构造好了;反之亦然,在你构造一个对象的时候根据定义没有变量被赋值给它。

想想强制所有子类都有一个继承的构造函数意味着什么。我认为,直接传入变量比类“神奇地”拥有一个带有一定数量参数的构造函数更清楚,因为它的父类有。

其他回答

大卫的答案是正确的。我想补充的是,您可能会从上帝那里得到一个信号,表明您的设计是一团糟的,“Son”不应该是“Super”的子类,相反,Super有一些实现细节,最好通过拥有Son提供的功能来表达,作为一种策略。

编辑:乔恩·斯基特的回答太棒了。

因为构造函数是一个实现细节——它们不是接口/超类的用户实际上可以调用的东西。当他们得到一个实例时,它已经被构造好了;反之亦然,在你构造一个对象的时候根据定义没有变量被赋值给它。

想想强制所有子类都有一个继承的构造函数意味着什么。我认为,直接传入变量比类“神奇地”拥有一个带有一定数量参数的构造函数更清楚,因为它的父类有。

因为构造子类对象的方法可能与构造父类的方法不同。您可能不希望子类的客户端能够调用父类中可用的某些构造函数。

举个愚蠢的例子:

class Super {
    protected final Number value;
    public Super(Number value){
        this.value = value;
    }
}

class Sub {
    public Sub(){ super(Integer.valueOf(0)); }
    void doSomeStuff(){
        // We know this.value is an Integer, so it's safe to cast.
        doSomethingWithAnInteger((Integer)this.value);
    }
}

// Client code:
Sub s = new Sub(Long.valueOf(666L)): // Devilish invocation of Super constructor!
s.doSomeStuff(); // throws ClassCastException

或者更简单:

class Super {
    private final String msg;
    Super(String msg){
        if (msg == null) throw new NullPointerException();
        this.msg = msg;
    }
}
class Sub {
    private final String detail;
    Sub(String msg, String detail){
        super(msg);
        if (detail == null) throw new NullPointerException();
        this.detail = detail;
    }
    void print(){
        // detail is never null, so this method won't fail
        System.out.println(detail.concat(": ").concat(msg));
    }
}
// Client code:
Sub s = new Sub("message"); // Calling Super constructor - detail is never initialized!
s.print(); // throws NullPointerException

从这个例子中,您可以看到您需要某种方式来声明“我想继承这些构造函数”或“我想继承除了这些以外的所有构造函数”,然后您还必须指定默认构造函数继承首选项,以防有人在超类中添加了新的构造函数……或者,如果您想“继承”父类中的构造函数,您可以只要求重复它们,这可以说是更明显的方式。

因为(超)类必须完全控制自己的构造方式。如果程序员认为在类的契约中提供默认(不带参数)构造函数没有意义,那么编译器就不应该提供这样的构造函数。

我不知道任何一种语言的子类继承构造函数(但是,我不是一个编程多面手)。

这里有一个关于c#的相同问题的讨论。普遍的共识似乎是,它会使语言复杂化,为基类中的更改引入潜在的严重副作用,并且通常在良好的设计中不应该是必要的。