6

Possible Duplicate:
Why does this() and super() have to be the first statement in a constructor?

Why exactly do subclass constructors have to explicitly call super class constructors? What is the reason for this?

Community
  • 1
  • 1
John W
  • 161
  • 1
  • 1
  • 6

4 Answers4

18

They don't.

If you don't explicitly call a superconstructor, it's equivalent to calling the parameterless superconstructor.

public class Sub
{
    public Sub()
    {
        // Do some stuff
    }
}

is equivalent to:

public class Sub
{
    public Sub()
    {
        super();
        // Do some stuff
    }
}

You do explicitly have to call a superconstructor if you want to specify arguments. That's pretty reasonable, IMO - would you really want the compiler guessing which arguments you wanted to supply?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Also, if your parent class do not have a parameterless constructor then you will need to explicitly call your super constructor with the necessary arguments. – Claudio Jan 10 '13 at 03:46
  • 4
    @ClaudioFernandez: Yes, I hoped that was implied - if there's no parameterless constructor, you can't implicitly call it :) – Jon Skeet Jan 10 '13 at 03:49
  • there is always a parameter less constructor in superclass created by jvm to see it just type javap classname on cmd prompt. – Abhishekkumar Jan 10 '13 at 04:06
  • 3
    @Abhishekkumar: No, there isn't. The compiler provides a default constructor *if no other constructor is specified*. If you specify a constructor with parameters but no parameterless constructor, then attempts to implicitly call a parameterless constructor from the subclass will fail. – Jon Skeet Jan 10 '13 at 04:18
  • Well, why not? The compiler could identify which superconstructor to call by looking at the signature. If number and type of parameters are the same, I don't see the problem on identifying this automatically and avoiding redundant code. Other languages do so. – Pere Feb 15 '17 at 09:30
  • @Pere: At that point, introducing a new constructor in a superclass changes the meaning of the code, which is a problem - unless you're also saying it shouldn't implicitly call `super()` if there *isn't* a match... – Jon Skeet Feb 15 '17 at 10:23
  • Sorry @JonSkeet but I don't get what you're talking about, nor think it is an answer to what I'm questioning. Let's say I have a constructor in my base class which takes one `String` parameter. If I extend my class, I have to explicitly declare a constructor in my child which takes a `String` and, if I don't want to implement further logic, simply call `super(myString);` on it. Why? Why cannot this be inferred automatically by the compiler? – Pere Feb 15 '17 at 15:43
  • @Pere: No, you don't have to declare such a constructor. You could declare any other kind of constructor that passes a string to the superclass. And suppose that `Child(String x) { super(x); }` constructor *were* applied automatically, how would you opt out of it? But further discussion in comments isn't a good idea - *potentially* a new question with a very specific set of alternative language rules would be appropriate, but it may well be better as a blog post to be honest. – Jon Skeet Feb 15 '17 at 17:26
  • @JonSkeet I would "opt out of it" by not calling the constructor passing a String in the subclass. Or overwriting that constructor in the child class to do nothing or throwing an error, who knows. To me, "inheritance" meant that until now: that all the methods from the parents are automatically inherited, including overloaded constructors. By the way, the title of the question seems to fit to my doubts, and I don't feel like it's been answered at all... – Pere Feb 16 '17 at 07:33
  • @Pere: How would you opt out of the constructor *existing* though? If a superclass constructor existed taking just a string, but you didn't want that constructor, how would you say you didn't want it? And how would you say you didn't want *any* extra constructors that might be added to the superclass later? Your "doubts" seem to be much wider than this question is about really though - your doubts are "Why aren't constructors inherited" which isn't really the same thing. – Jon Skeet Feb 16 '17 at 07:47
  • @JonSkeet Other OOP languages have exactly that behaviour, and that's what I expected in Java,too. It's called inheritance. If your parents buy a new property later, you will inherit it too. What if you want the new constructor to be available in the derived classes? You would have to manually add it to each of them... To me seems more natural to have them inherited by default, as with any new methods added to base (you have them inherited even if you don't want them - simply don't use them). In any case, you have to deal with any modifications you make to your code. Not a great example, IMO. – Pere Feb 16 '17 at 09:34
  • @Pere: *Some* other OOP languages, have exactly that behaviour, but others don't. C# works the same way in Java. If I were picking up one of the languages you're talking about, I'd be just as surprised as you are. Basically, I view how one *constructs* an object as very different from how one *uses* an object. "Just don't use things you don't want" is a really dangerous approach, IMO. That would make it impossible to have invariants - if everything inherited a parameterless constructor from `Object` for example, then what file would `new FileInputStream()` read from? – Jon Skeet Feb 16 '17 at 09:47
  • @Pere: Any *methods* you inherit from a superclass should still be applicable to a subclass... if not, it's not a good use of inheritance. The same does *not* hold for how you construct an object. I think we're going to have to agree to disagree though... – Jon Skeet Feb 16 '17 at 09:48
  • @JonSkeet well, the hypothetical case of `FileInputStream()` is already covered by the compiler not creating a default parameterless constructor if the base class already has some explicitly declared method that takes parameters. Constructors with parameters could be inherited by default if they (Oracle?) wished to and still keep the current restriction about parameterless constructor; it's all about conventions. And I don't see how that would affect to invariants. Also I'm tired of seeing inherited methods that simply throw an "unsupported" exception, although I agree it doesn't look so smart – Pere Feb 17 '17 at 15:15
  • @Pere: Now you're inventing more rules on the fly that you hadn't described before. That's why this is inappropriate for a comment thread. Again, I would urge you to write a blog post - or *at least* a new question presenting everything you're suggesting. This is not constructive as a comment thread. – Jon Skeet Feb 17 '17 at 15:19
  • @JonSkeet well, to me the rules are the same that I expressed in my first comment; the exception about the parameterless constructor already existed and was applying and I believe this discussion fits well as subquestions for the original one, although I agree this is too much discussion for a comment thread. – Pere Feb 17 '17 at 15:31
3

As mentioned above, you only have to invoke a super constructor if there isn't a default constructor in the parent class.

This is required because the parent class must be initialized by one of its constructors, and if there isn't a default constructor, the java compiler has no way of knowing which constructor to call, or what parameters need to be passed.

To better understand why at least one constructor in the parent must be called, consider the following:

class Person {
    private Person mother;
    private Person father;

    public Person(Person mother, Person father) {
        assert mother != null && father != null: "Parents can't be null!";

        this.mother = mother;
        this.father = father;
    }

    public boolean hasAnyLivingParents() {
        return mother.isAlive() || father.isAlive();
    }

    public boolean isAlive() { return true; }
}

If you create a Person directly, you must specify the mother and father of the person, and the hasAnyLivingParents() method expects these to be specified.

Now, consider you have a subclass, Employee, and you don't care about the parents of an Employee, so you want to write something like this:

class Employee extends Person {
    double salary;

    public Employee(double salary) { 
        this.salary = salary;
    }
}

This won't compile because we don't call a constructor of Person, and there isn't a default constructor. If this did compile, calling (new Employee(50000d)).hasAnyLivingParents() would always throw a NullPointerException, since nothing even initialized the mother and father fields.

In short, java requires that every class be initialized by some constructor. If there isn't a default constructor on a class, one of its other constructors must be called for the object to be initialized.

Yona Appletree
  • 8,801
  • 6
  • 35
  • 52
2

subclass implicitly call even default constructor present in super class which is non parameterised. We have to call explicitly when we pass parameters to the constructor.

Abhishekkumar
  • 1,102
  • 8
  • 24
  • That's clear; but why? – Pere Feb 15 '17 at 09:31
  • @Pere As it is stated in javadoc "You don't have to provide any constructors for your class, but you must be careful when doing this. The compiler automatically provides a no-argument, default constructor for any class without constructors. This default constructor will call the no-argument constructor of the superclass. In this situation, the compiler will complain if the superclass doesn't have a no-argument constructor so you must verify that it does. If your class has no explicit superclass, then it has an implicit superclass of Object, which does have a no-argument constructor." – Abhishekkumar Feb 15 '17 at 09:47
  • Thanks for answering, Abhishekkumar. I know this is an old question, but I was asking because you weren't answering the original one. We know we have to call explicitly when we don't pass parameters to the constructor. But what he was asking was why. We already knew what to do. Also the javadoc excerpt you cite has little to do with the question. We must be careful to have a non-argument constructor in the superclass; ok. But the question was a different one. Why do I have to do a `super()` which simply passes the parameters of the child constructor to the parent and nothing else? – Pere Feb 15 '17 at 10:15
  • Call to super() is required because the parent class must be initialized by one of its constructors, and if there isn't a default constructor, the java compiler has no way of knowing which constructor to call.Thus by internally or explicitly call we are initailizing class by its constructor – Abhishekkumar Feb 15 '17 at 11:27
  • Then the compiler could complain about the parent class not having a constructor. To me, again, this is not an answer at all. – Pere Feb 15 '17 at 15:41
  • @Pere Constructor calls are chained; any time an object is created, a sequence of constructor methods is invoked, from subclass to superclass on up to Object at the root of the class hierarchy. Because a superclass constructor is always invoked as the first statement of its subclass constructor, the body of the Object constructor always runs first, followed by the constructor of its subclass and on down the class hierarchy to the class that is being instantiated. There is an important implication here; when a constructor is invoked,it can count on the fields of its superclass to be initialized – Abhishekkumar Feb 16 '17 at 03:24
  • You are confusing me even else. Really, I don't need to know those details (and, by the way, are you sure it's really done that way?). I repeat: I don't want an explanation about how it's done. I'm just asking why isn't done in a different way, inferring which parent constructor should be called by just looking at the signature of the constructor, as other languages do, instead of having to manually doing it (if I can do it by hand, it can be done by the compiler). That's all. – Pere Feb 16 '17 at 07:27
1
class Parent
{ 
   Parent(int x) {}
}

class Child extends Parent
{
   Child(){} // will not compile.
}

Compiler tries to invoke super() as the first line of Child() constructor but the parent doesn't have no-arg constructor. So in this case you have to do it explicitly by calling super(5), for example.

Juvanis
  • 25,802
  • 5
  • 69
  • 87