Java Constructor Inheritance

145,596

Solution 1

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.

Solution 2

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, because you have to call your unique constructor, since"Super" doesn't have a default one.

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

Solution 3

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;
    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

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.

Solution 4

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.

Solution 5

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.

Share:
145,596

Related videos on Youtube

Alex Jones
Author by

Alex Jones

Programmer. Buenos Aires Argentina.

Updated on November 26, 2020

Comments

  • Alex Jones
    Alex Jones over 3 years

    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 constructor inheritance? Is there any benefit in not allowing this inheritance?

    • Derek Mahar
      Derek Mahar about 13 years
      I agree that the constructor in Son is repetitive. It is for this reason that C++ now allows derived classes to inherit base constructors (see www2.research.att.com/~bs/C++0xFAQ.html#inheriting). Note that I emphasize "allow" because the derived class must explicitly declare that it uses the constructors in the base.
    • Derek Mahar
      Derek Mahar about 13 years
      Like C++, Java would also benefit from syntax that permits constructor inheritance.
    • Grim
      Grim almost 10 years
      If you have a private final int foo; in the superclass Super, you can not assign a value to foo in the inherited Constructor in Son because its private in Super.
  • Alex Jones
    Alex Jones over 14 years
    Super is in reality a LayerSupertype (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
  • gustafc
    gustafc over 14 years
    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
    gustafc over 14 years
    ... which, for example, it does when the superclass has a default constructor and the subclass doesn't specify any constructors.
  • Jonathan Feinberg
    Jonathan Feinberg over 14 years
    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.
  • Alex Jones
    Alex Jones over 14 years
    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.
  • Jonathan Feinberg
    Jonathan Feinberg over 14 years
    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.
  • Derek Mahar
    Derek Mahar about 13 years
    Why not allow a derived class to optionally inherit its base constructors as does C++ (see www2.research.att.com/~bs/C++0xFAQ.html#inheriting)?
  • Derek Mahar
    Derek Mahar about 13 years
    A useful constructor syntax might be to allow a derived constructor to inherit the parameters of a base constructor and automatically forward these to the base constructor so that the derived constructor need not repeat these parameters.
  • Derek Mahar
    Derek Mahar about 13 years
    C++ now allows derived classes to inherit base constructors (see www2.research.att.com/~bs/C++0xFAQ.html#inheriting). This avoids the common idiom found in derived classes where a derived constructor does little more than declare the same parameters as in the base constructor and forward these to the base constructor.
  • Mononofu
    Mononofu over 12 years
    What prevents you from just declaring the parameterless constructor to be private if you don't need it?
  • Jon Skeet
    Jon Skeet over 12 years
    @Mononofu: Well it would certainly be annoying to have to create a constructor which would effectively create an unusable object and never be called, just to "remove" something which doesn't need to be provided anyway. Ick. I'd rather the language worked the way it does now :)
  • Jan
    Jan over 12 years
    @Mononofu But wait ... To use that correctly and confidently, you would then have to understand java's weird systems of inheritance for BOTH constructors AND visibility. Isn't the world confusing enough already? ;)
  • ryvantage
    ryvantage almost 10 years
    @JonSkeet - "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." Is that "there should be" => "there might be" or "there should be" => "there isn't but that'd be a good idea." ?? i.e., is there a way to "inherit" (for lack of a better word) all constructors of a superclass automatically??
  • Jon Skeet
    Jon Skeet almost 10 years
    @ryvantage:There isn't but sometimes it would be useful to be able to do so concisely. I don't know of any plans around that.
  • Naliba
    Naliba almost 10 years
    If you're using Eclipse, you can right-click -> "Source" -> "Generate Constructors from Superclass..." to quickly achieve this. I imagine other IDEs have similar functionality. It might be nice to have this as a feature of Java itself, but this works pretty well.
  • gcscaglia
    gcscaglia over 8 years
    "> What exactly would you expect: FileInputStream stream = new FileInputStream(); to do?" The same I expect Object o = new Object() to do: Nothing useful.
  • whoKnows
    whoKnows over 8 years
    Why not have a way for a base class to say "children should inherit this constructor?"
  • Jon Skeet
    Jon Skeet over 8 years
    @whoKnows: That suggests that the superclass knows the requirements of the subclass. If the subclass wants to force all its constructors to accept an extra parameter, it doesn't want to inherit the constructors from the superclass directly.
  • whoKnows
    whoKnows over 8 years
    And the base class can disable that constructor explicitly.
  • Jon Skeet
    Jon Skeet over 8 years
    @whoKnows: And again, how would the base class know? It's more something for the subclass to decide.
  • whoKnows
    whoKnows over 8 years
    @JonSkeet Whoops! I meant child class.
  • Jon Skeet
    Jon Skeet over 8 years
    @whoKnows: That makes adding a new constructor a difficult change. Given that it's easy to create a new constructor that chains to the old one, I think opting in explicitly seems fine to me.
  • whoKnows
    whoKnows over 8 years
    @JonSkeet How would that make adding a constructor a difficult change?
  • Jon Skeet
    Jon Skeet over 8 years
    @whoKnows: Anyone adding a constructor to a superclass could effectively bypass the guarantees that subclasses required. For example, suppose I have a subclass such that all constructors must specify a particular parameter - for example, a FileInputStream must always have a filename supplied. If a new superclass constructor was implicitly "inherited" (i.e. duplicated in the subclass) then that duplicate may break that invariant. I really think it's a bad idea.
  • whoKnows
    whoKnows over 8 years
    This is the exception rather than the rule. in this case, FileInputStream might want to disable that constructor, or the superclass might want to consider not making that constructor implicitly inherited. But in the vast majority of cases, the superclass would know that all of its children would want it to be implicitly inherited, or none.
  • Jon Skeet
    Jon Skeet over 8 years
    @whoKnows: I think we'll have to agree to disagree. I think it's very common for all constructors of a subclass to enforce an extra piece of initial data to be passed in. Anyway, I don't think Java is going to change now...
  • Monkeygrinder
    Monkeygrinder over 8 years
    @whoKnows I don't know that you could call this an "exception" so much as an example. Any superclass constructor that isn't used in the subclass could result in codebreaking behavior. This is true of many classes/programs, not just FileInputStream. It is better to require constructors from the superclass are called explicitly (which can be done very easily on an IDE like Eclipse anyway), than to assume that all imports/inherited constructors are properly restricted (and if not restricted, then inherited). What you are proposing would be very difficult to troubleshoot/maintain.
  • Monkeygrinder
    Monkeygrinder over 8 years
    (I also do agree with the notion of an optional "pass-through" though... but I'm not sure how much grief that would actually save in the long run)
  • u8y7541
    u8y7541 over 7 years
    FileInputStream would work because it overloads the constructor.
  • Jon Skeet
    Jon Skeet over 7 years
    @u8y7541: No, you've missed the point - if all constructors are inherited, then it would end up indirectly inheriting the parameterless constructor from Object. Sure, the useful overloads would still exist - but so would the useless one.
  • Benjy Kessler
    Benjy Kessler over 7 years
    My two cents: Java already has a mechanism whereby classes come with a default constructor but once a custom constructor is provided the default is removed. I think this mechanism could still work if default is defined as "all my superclass' constructors" instead of "constructor with no arguments". I think this will solve most of the problems mentioned above. Since FileInputStream declares a constructor that accepts a String this will invalidate the default constructor inherited from Object.
  • Jon Skeet
    Jon Skeet over 7 years
    @BenjyKessler: It wouldn't help in the common case where you basically want "all the constructors from the superclass, but with one extra parameter on each of them". So it would prevent that one specific problem, but not be a useful feature in other cases. It would also make the language more complex, IMO. It's clearly too late to change now anyway, of course...
  • Benjy Kessler
    Benjy Kessler over 7 years
    @JonSkeet, that indeed be a very hard use case to support and indeed I would think very confusing and ambiguous. Consider Base that receives two ints and Derived that receives three. How would the compiler know how to choose the correct arguments to pass to Base? This seems confusing and wouldn't add much to the existing language. But I find myself often writing classes with the exact same constructors as the base class and this would help. As for the second point, a girl can dream can't she?!
  • Sarah Messer
    Sarah Messer about 7 years
    Python does: stackoverflow.com/a/6536027/2112722. Python also splits up the "constructor" phase into __new__() and __init__() methods, and has a very different approach to polymorphic methods. See pythonconquerstheuniverse.wordpress.com/2010/03/17/…
  • Alvaro
    Alvaro about 7 years
    Any non typed language allows this
  • The incredible Jan
    The incredible Jan over 6 years
    Your examples don't convice me. Just because you code bugs on purpose it is no valid argument against constructor inheritance. NullPointerExceptions are completely normal if you botch (and sometimes even if you don't).
  • gustafc
    gustafc over 6 years
    @TheincredibleJan The point is that one important thing constructors are used for, is enforcing class invariants. Implicit constructor inheritance would make it much more complicated to give any guarantees about instances of a class (impossible, even, if you consider that constructors may be added to superclasses).
  • Ralf Kleberhoff
    Ralf Kleberhoff over 6 years
    In 20 years of Java experience, my subclass constructors more often significantly differed from the superclass ones than they were identical or even similar. So I'm happy with Java's design decision.
  • LowKeyEnergy
    LowKeyEnergy over 4 years
    This is not a good example. Your problem is that you are casting non-Integer Numbers to Integer. It has nothing to do with inheritance.
  • gustafc
    gustafc over 4 years
    @LowKeyEnergy no, the problem is that being able to bypass constructors would deprive you of the only way you have to enforce class invariants. But, I admit my example could be more succinct - the point made in the accepted answer is more to the point; that everything would have a default constructor.