views:

418

answers:

9

Hi,

I was wondering why in java constructors are not inherited? You know when you have a class like this:

public class Super {

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

}

Later when you inherit from Super, java will complain that there is no default constructor defined. The solution is obviously something like:

public class Son extends Super{

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

}

This code is repetitive, not DRY and useless (IMHO)... so that brings the question again:

Why java doesn't support constructors? is there any benefit in not doing it?

Thanks.

+2  A: 

when you inherit from Super this is what in reality happens:

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

}

So, that is the reason cause you have to call to your unique constructor, cause "Super" doesnt have a default one.

Now, trying to guess why Java doesn't support constructor inheritance, probably cause a constructor only have sense talking about concrete instances, and you shouldn't be able to create an instance of something that you don't know how is defined (by polymorphism).

David Santamaria
+2  A: 

Because constructors are an implementation detail - they're not something that a user of an interface/superclass can actually invoke at all. By the time they get an instance, it's already been constructed; and vice-versa, at the time you construct an object there's by definition no variable it's currently assigned to.

Think about what it would mean to force all subclasses to have an inherited constructor. I argue it's clearer to pass the variables in directly than for the class to "magically" have a constructor with a certain number of arguments just because it's parent does.

Andrzej Doyle
+2  A: 

David's answer is correct. I'd like to add that you might be getting a sign from God that your design is messed up, and that "Son" ought not to be a subclass of "Super", but that, instead, Super has some implementation detail best expressed by having the functionality that Son provides, as a strategy of sorts.

EDIT: Jon Skeet's answer is awesomest.

Jonathan Feinberg
Super is in reality a LayerSupertype (http://martinfowler.com/eaaCatalog/layerSupertype.html) of my service layer. And I need the dependencies injected in the constructor to support DI. My design is not _messed up_
Pablo Fernandez
Well, that's a matter of opinion! It seems to me that if your hierarchy is distorted to feed the requirements of your buzzword framework, that might in itself be a Sign from Above.
Jonathan Feinberg
Please explain why you say that my hierarchy is _distorted_. And I've never mentioned a buzzword framework, in fact I'm just using Guice + Plain old servlets.
Pablo Fernandez
I don't know whether your design is distorted, nor whether it's badly designed. I'm merely saying that if your subclass differs from its superclass *merely* by providing some difference in strategy, then in *may* be better expressed as a thing that the superclass *has* rather than *is*. I then said that if that's the case, but you still must design your software as a parent-child reltionship in order to support the needs of some framework (whether it's DI or whatever), then that's "distortion"! But I have no idea about how your software is designed.
Jonathan Feinberg
+1  A: 

Constructors are not polymorphic.
When dealing with already constructed classes, you could be dealing with the declared type of the object, or any of its subclasses. That's what inheritance is useful for.
Constructor are always called on the specific type,eg new String(). Hypothetical subclasses have no role in this.

Rik
What the OP probably asks is "why do I have to make the super calls, when the compiler is perfectly capable of generating them for me?"
gustafc
... which, for example, it does when the superclass has a default constructor and the subclass doesn't specify any constructors.
gustafc
+11  A: 

Suppose constructors were inherited... then because every class eventually derives from Object, every class would end up with a parameterless constructor. That's a bad idea. What exactly would you expect:

FileInputStream stream = new FileInputStream();

to do?

Now potentially there should be a way of easily creating the "pass-through" constructors which are fairly common, but I don't think it should be the default. The parameters needed to construct a subclass are often different from those required by the superclass.

Jon Skeet
A: 

I don't know any language where subclasses inherit constructors (but then, I am not much of a programming polyglott).

Here's a discussion about the same question concerning C#. The general consensus seems to be that it would complicate the language, introduce the potential for nasty side effects to changes in a base class, and generally shouldn't be necessary in a good design.

Michael Borgwardt
+2  A: 

Because constructing your subclass object may be done in a different way from how your superclass is constructed. You may not want clients of the subclass to be able to call certain constructors available in the superclass.

A silly example:

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

Or even simpler:

class Super {
    private final String msg;
    Super(String msg){
        if (msg == null) throw new NullPointerException();
        this.msg = msg;
    }
}
class Sub {
    private final String detail;
    Super(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

From this example, you see that you'd need some way of declaring that "I want to inherit these constructors" or "I want to inherit all constructors except for these", and then you'd also have to specify a default constructor inheritance preference just in case someone adds a new constructor in the superclass... or you could just require that you repeat the constructors from the superclass if you want to "inherit" them, which arguably is the more obvious way of doing it.

gustafc
A: 

A derived class is not the the same class as its base class and you may or may not care whether any members of the base class are initialized at the time of the construction of the derived class. That is a determination made by the programmer not by the compiler.

ChadNC
A: 

Because a (super)class must have complete control over how it is constructed. If the programmer decides that it doesn't make sense to provide a default (no args) constructor as part of the class's contract, then the compiler should not provide one.

Loadmaster