Java构造函数继承

Pab*_*dez 179 java inheritance constructor

我想知道为什么java构造函数不会被继承?你知道什么时候有这样的课:

public class Super {

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

}
Run Code Online (Sandbox Code Playgroud)

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

public class Son extends Super{

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

}
Run Code Online (Sandbox Code Playgroud)

这段代码是重复的,而不是干的和无用的(恕我直言)...所以这又带来了问题:

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

Jon*_*eet 197

假设构造函数继承......然后,因为每个类最终从对象派生,类将结束与一个参数的构造函数.这是个坏主意.你到底想要什么:

FileInputStream stream = new FileInputStream();
Run Code Online (Sandbox Code Playgroud)

去做?

现在可能应该有一种方法可以轻松创建相当常见的"传递"构造函数,但我不认为它应该是默认值.构造子类所需的参数通常不同于超类所需的参数.

  • 为什么不*允许*派生类可选地继承其基本构造函数,如同C++一样(参见www2.research.att.com/~bs/C++0xFAQ.html#inheriting)? (33认同)
  • @Mononofu:那么必须创建一个能够有效地创建一个不可用的对象并且永远不会被调用的构造函数肯定会很烦人,只是为了"删除"无论如何都不需要提供的东西.伊克.我宁愿这种语言按现在的方式工作:) (5认同)
  • 是什么阻止你只是声明无参数构造函数是私有的,如果你不需要它? (4认同)
  • 一个有用的构造函数语法可能是允许派生构造函数继承基本构造函数的参数并自动将它们转发到基础构造函数,以便派生构造函数不需要重复这些参数. (3认同)
  • @Mononofu但是等等......为了正确而自信地使用它,你必须理解java的BOTH构造函数和可见性的怪异继承系统.难道世界已经不够混乱吗?;) (2认同)

Dav*_*ria 30

当你从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();
  }

}
Run Code Online (Sandbox Code Playgroud)

所以,这就是原因,因为你必须调用你的独特构造函数,因为"超级"没有默认构造函数.

现在,试图猜测为什么Java不支持构造函数继承,可能是因为构造函数只有在谈论具体实例时才有意义,而当你不知道它是如何定义的时候你不应该创建一个实例(通过多态性).


gus*_*afc 11

因为构造子类对象可能以与构造超类的方式不同的方式完成.您可能不希望子类的客户端能够调用超类中可用的某些构造函数.

一个愚蠢的例子:

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
Run Code Online (Sandbox Code Playgroud)

甚至更简单:

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
Run Code Online (Sandbox Code Playgroud)

从这个例子中,你看到你需要某种方式来声明"我想继承这些构造函数"或"我想继承除了这些构造函数之外的所有构造函数",然后你还必须指定一个默认的构造函数继承偏好,以防万一有人在超类中添加一个新的构造函数...或者如果你想"继承"它们,你可能只需要重复超类中的构造函数,这可能是更明显的方法.


And*_*yle 5

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

想想强制所有子类具有继承的构造函数意味着什么.我认为将变量直接传递给类比使用"神奇地"拥有一个具有一定数量参数的构造函数更为明确,因为它是父类.