Java构造函数继承

我想知道为什么在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不支持构造函数继承?不允许这种继承有什么好处吗?

150387 次浏览

当你从Super继承时,这是现实发生的情况:

public class Son extends Super{


// If you dont declare a constructor of any type, adefault one will appear.
public Son(){
// If you dont call any other constructor in the first line a call to super() will be placed instead.
super();
}


}

这就是原因,因为你必须调用你唯一的构造函数,因为"Super"没有默认的构造函数。

现在,尝试猜测为什么Java不支持构造函数继承,可能是因为构造函数只有在谈论具体实例时才有意义,并且当您不知道如何(通过多态性)定义某个对象时,您不应该能够创建该对象的实例。

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

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

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

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

构造函数不是多态的 当处理已经构造的类时,可以处理对象的声明类型或其任何子类。这就是继承的作用。
构造函数总是在特定类型上调用,例如new String()

假设构造函数继承了…那么因为每个类最终都从Object派生,每一个类将以一个无参数构造函数结束。这是个坏主意。你的期望是什么?

FileInputStream stream = new FileInputStream();

做什么?

现在应该有一种潜在的方法来轻松地创建“传递”构造函数,这是相当常见的,但我不认为它应该是默认的。构造子类所需的参数通常不同于父类所需的参数。

我不知道任何语言,其中子类继承构造函数(但是,我不是一个编程多门语言)。

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

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

举个愚蠢的例子:

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

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

派生类与其基类不是同一个类,您可以也可以不关心基类的任何成员是否在构造派生类时进行了初始化。这是由程序员而不是编译器决定的。

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

从某种意义上说,你确实继承了构造函数,你可以简单地调用super,如果合适的话,只是它很容易出错,因为其他人已经提到过,如果它默认发生的话。编译器不能假定什么时候合适,什么时候不合适。

编译器的工作是提供尽可能多的灵活性,同时降低复杂性和意外副作用的风险。