Matt Mills
Matt Mills

Reputation: 8792

Can't call supertype constructor directly - why not?

I have the following example classes in Java:

public class A { }

public class Super {
    protected Super() { }
    public Super(A a) { }
}

public class Sub extends Super { }

public class Consumer {
    public Consumer() {
        Sub sub = new Sub(new A()); //compiler error
    }
}

The compiler error states that the arguments cannot be applied to the default constructor in Sub, which is perfectly understandable.

What I'm curious about is the rationale behind this decision. Java generates the default empty constructor in Sub; why can't it call it behind the scenes in this case? Is this primarily a case of sane hand-holding, or is there a technical reason?

EDIT

I'm aware that this is a language limitation. I'm curious about why it is a language limitation.

EDIT 2

It seems that, as is often the case, I was too close to the code I was actually working in to see the big picture. I've posted a counter-example in the answers below that shows why this is a Bad Thing®.

Upvotes: 6

Views: 645

Answers (5)

Matt Mills
Matt Mills

Reputation: 8792

I'm putting this out as a technical reason for this behavior; I'm in agreement with several other answers that this could be semantically confusing.

Consider the following example:

public class A { }

public abstract class Super {
    protected Super() {
        // perform time consuming, destructive, or
        // otherwise one-time operations
    }

    public Super(A a) {
        this();
        // perform A-related construction operations
    }
}

public class Sub extends Super { }

public class Consumer {
    public Consumer() {
        Sub sub = new Sub(new A());
    }
}

When the Sub is constructed, in this case the default constructor on Sub would be called, which would chain to the default constructor on Super (because that's the magic the language defines). Then, the call to Super(A) would invoke logic that is designed to be run once, at construction. This is obviously not what the developer intends.

Even without the this() call in the Super(A) constructor, the developer's intention cannot be determined; the constructors may be mutually exclusive for some reason.

Upvotes: 0

Garrett Hall
Garrett Hall

Reputation: 30022

Base classes need to call super constructors in order to ensure an object is properly instantiated. For instance consider:

class Super {
   final String field1;

   public Super(String field1) {
      this.field1 = field1;
   }
   ...
}


class Base extends Super {
   final String field2;

   public Base(String field2) {
      this.field2 = field2;
   }
   ...
}

Does Base's constructor override the Super constructor? If so, then field1 is no longer guaranteed to be initialized, making inherited methods behave unexpectedly.

The moment you add a non-default constructor to the subclass then inherited constructors stop working. I think it'd be a confusing and rarely useful feature it was added to the language, although technically I can see no reason why it wouldn't be possible.

Upvotes: 2

Mark Peters
Mark Peters

Reputation: 81074

I think it's an issue of both readibility and not assuming intent. You say

Java generates the default empty constructor; why can't it call it behind the scenes in this case?

Yet to me, it would make much more sense for Java to implicitly call the Super(A) constructor "behind the scenes" than to call the Super() constructor, disregarding A.

And there you have it. We already have two disparate assumptions about what should (or could) happen in this case.

One of the Java language's core principles is transparency. As much as possible, the programmer should be able to see by looking at the code what will happen, sometimes at the expense of convenience or magic at the syntax level.

A parallel tenet to that is not assuming intent: in cases where the programmer's intentions seem ambiguous, the Java language will sometimes favour a compile error rather than automatically chosing a default through some (arbitrary or otherwise) selection algorithm.

Upvotes: 2

mikek3332002
mikek3332002

Reputation: 3562

You've overidden the default public constructor, so there isn't anything to call.

So the class Sub is equivalent to

public class Sub extends Super
{
    protected Sub(){}
    public Sub(A a) { }
}

It would because its

  • Sane behaviour - Behaves as specified by the programmer, and it also follows the concept of inheritance in OOP languages
  • Following its C++ legacy

Upvotes: 0

Bhesh Gurung
Bhesh Gurung

Reputation: 51030

public class Sub extends Super { }

does not have the constructor Sub(A a), it only has the default constructor Sub().

Constructors are not inherited.

Upvotes: 2

Related Questions