Java Constructor Inheritance - java

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?

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.

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).

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.

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.

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.

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.

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.

You essentially do inherit the constuctors in the sense that you can simply call super if and when appropriate, it's just that it would be error prone for reasons others have mentioned if it happened by default. The compiler can't presume when it is appropriate and when it isn't.
The job of the compiler is to provide as much flexibility as possible while reducing complexity and risk of unintended side-effects.

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.

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.

Related

Can we avoid inheritance without using final keyword?

I just want to know that can i have 2 classes A and B.
I don't want to allow class B to extends class A.
What technique should i apply in class A so class B cannot inherit class A.
Don't want to make class A final. Any other solution instead of making class A final?
In fact, the practice that I try to follow, and that Josh Bloch recommends, in his Effective Java book, is exactly the inverse rule of the one you've been told: Unless you have thought about inheritance, designed your class to be inherited, and documented how your class must be inherited, you should always disable inheritance.
I would recommend reading this chapter of Effective Java (you won't regret buying it), and showing it to the person who told you about this rule.
The most obvious reason to disallow inheritance is immutability. An immutable object is simple to use (only one state), can be cached, shared between many objects, and is inherently thread-safe. If the class is inheritable, anyone can extend the class and make it mutable by adding mutable attributes.
https://stackoverflow.com/a/10464466/5010396
This is not possible in "nice ways". The java language allows you to either have the final keyword on your class definition, or to not have it.
As pointed out by others: you can make all constructors private, then subclassing becomes practically impossible, as the subclass constructors have no super class constructor to call.
In case you need to instantiate A, you could still have a factory method, like:
public class A {
private A() { ... }
private A(String foo) { ... }
public static A newInstance(String foo) { return new A(foo); }
for example.
But keep in mind: code is written for your human readers. If your intent is to have a final class, then the correct answer is to use that keyword final.
Plus: making your class final allows the JIT to do a few more things, as it doesn't have to worry about polymorphism at any point (so it can directly inline method code, without any additional checks). So using final can result in slightly improved performance. On the other hand, it limits your ability to unit test things (for example: standard Mockito can't mock final classes).
You can mark the constructor of A class as private. :)
PS: If you also want to avoid reflection attacks then throw some Error from constructor
and also mark it private.
You have an option to restrict in constructor like this.
if (this.getClass() != MyClass.class) {
throw new RuntimeException("Subclasses not allowed");
}
For further details check the post.
https://stackoverflow.com/a/451229/6742601
I don't understand the specific use case of your requirement but this could work.
If you are open to make changes in B
In B's every constructor check for is it is an instance of A then throw an error.
if(A.class.isAssignableFrom(B.class)) {
System.out.println(true);
throw new IllegalStateException();
}
else
System.out.println(false);
You can do one of the following to avoid inheritance without using final keyword:
Use private constructor(s).
Mark every method final so children can't override them.
Throw Runtime exception in the constructor if want to limit inheritance for some unwanted children (although v.rude) e.g
if (this.getClass() != FavoriteChild.class) throw new RuntimeException("Not Allowed")

Forcing subclasses to have a particular factory method or constructor

I am 70% confident that this is impossible, but is there a way to make sure that subclasses have a particular constructor or factory method?
In this case, I am trying to create a StringSerializable that would require subclasses to have the following methods
toString, which converts the object to a String.
fromString, which gets an instance from a String.
Obviously, in the first case, I can just make toString abstract. On the other hand, having a nonstatic fromString seems to be problematic. However, I can't create an abstract static method. I also do not think that a constructor is entirely appropriate.
You're correct; it's impossible to force it at compile time. There are various tricks you could do at runtime (such as using reflection in tests), but that's about it.
But ask yourself: why do you want to require that? You can't dynamically invoke a static method or constructor (except through reflection), so how exactly would you use those required factories, if you had them?
If it's just for consistency in the code (which is a good thing!), then you'll just have to ensure that consistency as you develop the code base. A comment in the base class can go a long way here, as can code reviews and other "soft" techniques.
If you plan to use the factories in reflection, then similar reflection can be used in tests to make sure that each subclass has the bits it needs.
Another option is to create a non-static factory:
public interface FooMaker() {
Foo create(String arg);
}
... and use that, rather than a static fromString method.
There again you have the same problem of "how do I ensure that every subclass has a FooMaker implementation?" and again I would say that you shouldn't worry about that. If you make the FooMaker the "starting point" of your code, rather than the subclasses, then it doesn't matter what the subclasses are doing; all that matters is that your FooMakers give you a way of going from string to Foos, and each Foo has a way of going back to a string.
the following code does ensure that every subclass needs to implement the static method, if the subclass does not implement the method it will fail when classes are constructed, as close as you can get to a compile time error, but not at compile time
the exception thrown is very clear and the programm will instantly fail when started
public abstract class Base {
static Functional test;
static {
if(test == null) {
throw new RuntimeException("You need to provide an implementation for the implemntMe method in class base");
}
}
private interface Functional {
Base implementMe(int whatever, boolean anotherParameter);
}
public static void main(final String[] args) {
}
}
the private interface construct ensures that only lambdas can be used to implement the method
a subclass would have to look like this
public SubClass extends Base {
static {
test = (int whatever, boolean anotherParameter) -> {
Subclass tmp = new Subclass();
//construct object
tmp.setWhatever(whatever);
return tmp;
}
}
}
lamdas are like inline methods that implement a functional interface, an interface which has only one abstract method
you can also declare the interface publicly at any other place and implement it with an anonymous inner class,
but my way makes sure that programers have to copy and paste code to reuse it,
or need to copy the object of Functional from another class

Safety of subclass data when returned as superclass

I'm having some trouble finding the specifics on what happens when you return a subclass in a method of superclass type in Java. For example:
public class SuperClass
{
int a;
}
public class SubClass extends SuperClass
{
int b;
}
SuperClass superObj;
SubClass subObj;
private SuperClass getObject ()
{
return subObj;
}
public static void main (...)
{
superObj = getObject();
}
What exactly happens to subObj when it's returned as its superclass? I realise while typing this example that I could probably just as easily test it myself, but i'm still curious as to what the process is exactly when this happens, and whether it's considered good (if it works, that is) or bad practice.
I'm asking because I'm currently working on a project in which I have two abstract base classes, and several subclasses for each of them. I'm trying to find out good/bad ways to handle having to change from one subclass to another while still using the convenience polymorphism adds when using abstract base classes.
EDIT: I fixed main and the class declarations, sorry about that.
Casting does not fundamentally change an object to a different type, it simply tells the compiler to view the object as its superclass (or subclass, when downcasting). In your example, superObj is still an instance of the SubClass type, but it now appears to be a SuperClass. What this means is that if you try to reference superObj.b, you will get a compilation error (since b does not exist in SuperClass). However you could reference (SubClass)superObj.b. In this case you are telling the compiler to consider subClass as an instance of SubClass (which it really is).
Let's take this a step further and add another class to your code:
public class SisterClass extends SuperClass
{
int c;
}
Without changing anything else in your code (other than the syntax problems), you try to reference ((SisterClass)superObj). This will compile but fail with a ClassCastRuntime runtime error. Although SisterClass is a subclass of SuperClass, superObj is not an instance of SisterClass. So, you can only cast to what the object actually is.
There are some oddities in your code (defining a method inside main?), but that not withstanding... The method getObject will not change your subObj, it will simply return a reference to it that looks like type SuperClass. By "looks like" I mean that it will only expose any methods or members from SuperClass. However, if you take that returned value and attempt to downcast it to SubClass, the cast will succeed and you will find the field/methods from SubClass will work as you expect without any loss of information from having been returned as SuperClass.
SubClass is extension of SuperClass
you are just casting it down to its base class, all extensions are not available, you should not be looking to try and get them back to Implementations as you would be guessing what that are, as you could extend it numerous times in various ways,
The returned class would have a but not b

Why does a sub-class call super() by default?

This question has been bugging me for a while now, and I haven't found a good answer (other than "that's just how it is").
Let me give some background code, to show what I'm talking about.
class Note {
private final String name = "Note";
public Note() {
System.out.println(name);
}
// ...
}
class Todo extends Note {
private final String name = "Todo";
public Todo() {
System.out.println(name);
}
// ...
}
// ...
Note note = new Todo(); // case 1
Todo todo = new Todo(); // case 2
So how come both case 1 and case 2 print out:
Note
Todo
This makes no sense, since Todo() (constructor) does not call super() (at least not visibly). Why would the sub-class have to call the parents default constructor, why not just require any sub-class to implement a constructor?
I read a couple questions related to this, but none answer why.
Edit:
I guess my example was kind of poor, but It's actually a derivative from a Java 7 Certification question.. From the collective of answers I now understand why. Let me provide a better example:
public Note {
private String description;
public Note() {
description = "I'm a Note";
}
public Note( String description ) {
this.description = description;
}
// getters/setters/etc.
}
public Todo extends Note {
// field vars..
public Todo() {
// empty constructor
}
// getters/setters/etc..
}
So now this makes more sense, since when Todo is created, if super() was not inserted behind the covers, the Note aspect of the Todo would not be initialized. Which would be pointless to have a sub-class in that case. Thanks all!
The subclass constructor has to call some constructor. If you haven't told it which to use, it will use the default constructor.
The alternative is having variables in the superclass be completely uninitialized and yet accessible by the subclass and/or its methods, which would be spectacularly bad.
The decision to silently call the default superclass constructor, rather than e.g. fail to compile, is debatable, though, but I suspect it's tied to the existence of a "default constructor" in the first place.
FYI, your question also suggests that you might be getting confused about inheritance. The Note.name and the Todo.name fields are completely separate: you cannot override a field in a subclass, only methods.
The question can be separated into two parts.
Why does any constructor of the superclass have to be called? This is easy: the constructor is responsible for setting up the state of the object, and since there can be state in the superclass not visible to the subclass code (i.e. private fields), this can only be dealt with by calling a constructor of the superclass.
Why don't you have to call super() explicitly? This is just a fairly arbitrary design decision made in Java to make code look simpler. It ties in nicely with the concept of a default constructor (i.e. the implied no-arg constructor that exists in classes that don't have an explicit constructor defined), although as can be seen in your example, it also works when you have a no-arg constructor explicitly defined in the superclass.
You don't have to call a superclass constructor explicitly. And it is not necessary to have a super() or super(arguments) call in a subclass constructor. If you do not specify that, the compiler will automatically add a call to the no-arguments superclass constructor.
If the superclass does not have a no-arguments constructor, then you must explicitly call super(arguments) in each subclass constructor.
The reason why both case print out Note and Todo is that you create using operator new always instance of class Todo. If you have wrote
Note note = new Note();
Note todo = new Todo();
Then result would be:
Note
Note
Todo
The cause of that behavior is Polymorphism.
To answer why constructor must call super constructor to create itself is easy to picture. As it use the elements of that super class that class must be created first, so the class that inherit it can operate on it.
In your example, the parent's constructor doesn't do anything with the object.
Generally, a constructor does some construction of the object by setting fields. These fields are known to the constructor of the that class and might not be settable or accessible in another class and you would wouldn't want to duplicate all that code in every sub-class (that is already in the parent class) just so the parent fields are set correctly.
So it makes sense for each class to initialise the fields it knows about and not depend on the behaviour of sub-class to much to behave correctly. This allows you to change one class without having to change it's sub classes. e.g. adding or changing a field.
In fact, it does. The super() call is automatically added even if you don't write it. It is the first instruction in Todo's constructor.
To test this yourself, just create a new Note constructor with a parameter and delete the empty one. See what happens now:)
Why does this happens? Well, it's simple: because this is how it's implemented.
The documentation says it all:
If a constructor does not explicitly invoke a superclass constructor,
the Java compiler automatically inserts a call to the no-argument
constructor of the superclass. If the super class does not have a
no-argument constructor, you will get a compile-time error. Object
does have such a constructor, so if Object is the only superclass,
there is no problem.
That's just how it is! :)
To me it all make sense because the main reason you write your code in Object Oriented Programming paradigm is to reuse existing code.
There are many ways you can reuse, one of them is to inherit a class (ie: creating a subclass).
When you inherit a class, then you also inherit how that class is created.
In my opinion Java will be a much more confusing language if such behavior doesn't exist

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Ā®.
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.
public class Sub extends Super { }
does not have the constructor Sub(A a), it only has the default constructor Sub().
Constructors are not inherited.
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.
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
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.

Categories

Resources