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
Related
This question already has answers here:
Why call super() in a constructor?
(8 answers)
Closed 5 years ago.
I'm a Java beginner learning about Java compiler rules as below:
If the class has no super class, extend it to Object class
If the class has no constructor, add a default no-parameter constructor
If the first line of the constructor is not "super()" or "this()", add "super()" to call the default constructor of the super class.
I understand that all objects we create are derived from the super class Object.
My question is what does the constructor in the Object class do when called?
Edit: My question is about what the constructor does in the class Object? I'm aware that subclasses call superclass's constructor by default.
For example, I have the following code (where I explicitly extend to Object and call super() to illustrate what the compiler does). My question is, what does the call to super() do?
public class Person extends Object
{
private String name;
public Person(String n)
{
super();
this.name = n;
}
}
My question is, what does the call to super() do?
It calls the default constructor for java.lang.Object. And to answer what you seem to be really asking, from the Java Language Specification, #8.8.9
8.8.9. Default Constructor
If a class contains no constructor declarations, then a default constructor is implicitly declared. The form of the default constructor for a top level class, member class, or local class is as follows:
The default constructor has the same accessibility as the class (§6.6).
The default constructor has no formal parameters, except in a non-private inner member class, where the default constructor implicitly declares one formal parameter representing the immediately enclosing instance of the class (§8.8.1, §15.9.2, §15.9.3).
The default constructor has no throws clauses.
If the class being declared is the primordial class Object, then the default constructor has an empty body. Otherwise, the default constructor simply invokes the superclass constructor with no arguments.
Note the final paragraph.
All Java classes that don't have any explicit superclass, extend from Object, except for Object itself. There's no need to make it explicit in your code, the compiler will take care of.
Also, the super() call in the constructor will invoke the constructor of Object. If you look at the implementation, you'll see that Object doesn't have any constructor at all, so it'll use an implicit empty constructor which does nothing. Details such as constructing a vtable to make sure that the inherited methods are there to use or initialising the object's monitor are not part of the constructor but are performed by the JVM implementation when the new operator is called.
public Object() {
}
The Object class has few methods that come handy in most of the classes. For example, the infamous toString() is implemented in the Object class. Also, the hashCode() is implemented there.
I'd recommend you to have a deep look at the Object.class file to understand what methods are inherited in every single Java class.
Regarding your 3 rules at the top, are "good" for academic purposes but never used in reality. You'll never see an explicit extends Object, and only call the super() or this() when you need to overwrite the default behaviour.
Also, avoid abusing of inheritance and use more composition (implement an interface), although, it depends on the every use case.
For example, I have the following code (where I explicitly extend to
Object and call super()). My question is, what does the call do
super() do?
Actually, Object() does nothing.
Now you should not reduce the constraint to invoke super() (with args or not) for any subclass constructor to the case where you have a class that doesn't extend a class explicitly.
This case is the only one where invoking super() may seem not really useful.
But as soon a class extends a class distinct from Object, this constraint makes really sense as the child construction has to apply first its parent construction.
But the language specifies this point in a general way. It has no exception for classes that extend directly Object.
Probably because, it makes things more simple and that is not a real constraint as the compiler adds for you the call to the super default constructor : super().
When I write a constructor in my java class, I typically do not invoke super() in there. When I generate the constructor from eclipse source code editor, why does it always add the super() in there?
Am I wrong for not adding this by default in the constructors I write? Any thing wrong with leaving the super() call in the constructor if I decide to use eclipse code generator?
As #Kon correctly points out, there is an implicit call to the default super constructor anyway (this can be easily verified by checking the bytecode with javap -c). If you don't want Eclipse to make it explicit, simply check the "Omit call to default constructor super()" checkbox at the bottom of the constructor creation GUI.
Am I wrong for not adding this by default in the constructors I write?
No, as long as long as you're referring to the default super constructor call super(). If the super constructor takes parameters, for example, then you need to make the call explicit.
Any thing wrong with leaving the super() call in the constructor if I decide to use eclipse code generator?
No, not at all.
As #Kon mentioned in his comment, an empty constructor in Java contains an implicit call to the superclass constructor.
Moreover, a non-empty constructor without an explicit call to super() will have an implicit call at the top.
The only time when it is wrong to leave the super() call there is if you intend to call a different superclass constructor yourself, with parameters.
See this question for more details.
Update: Consider the following code, which illustrates the scenario where it is wrong to leave the super() generated by eclipse.
public class Foo{
public Foo(int a, int b) {
System.out.println("Foo constructor with-args is called");
}
public Foo() {
System.out.println("Foo with no-args is called");
}
}
class Bar extends Foo {
public Bar() {
// Implicit call to super()
super();
// Explicit call to super(a,b);
// This will not compile unless the call above has been removed.
super(1,2);
}
}
Nothing wrong it's just a coding style preference. Some people like to write code that is implicit and some don't.
If you don't call super constructor from your child class constructor compiler will place call to super's default constructor in byte code for you.
See this SO question as well
This is probably obvious, so bear with me.
YES, I KNOW THAT java.io.File has no default constructor.
The problem is that When I try to extend java.io.File, it says "Cannot find constructor File() in java.io.File" even though I am overriding the default constructor in java.lang.Object.
Here is my code:
AbsRelFile.java
import java.io.File;
public class AbsRelFile extends File {
File f;
private AbsRelFile(){
}
}
This gives me an error, even though I am overriding the constructor.
NOTE: This class is not finished. Don't make a comment about why wouldn't I need this or a comment about how this class is useless. I just started writing it before I got this Error.
Because you didn't make an explicit call to super(...) in your default constructor, it is implicitly attempting to call the default constructor for the super class, which, as you point out, doesn't exist in this case (the case of super being a File). The solution to your problem is to make a call to the super constructor in your default AbsRelFile() constructor. If you wan't to provide a default constructor for your class, you're going to need to call super(...) with some default values.
When you define a constructor, Java inserts an implicit call to the super constructor as the very first line of the constructor. So your constructor is equivalent to:
private AbsRelFile(){
super();
}
Since there is no default constructor in the super class File, it gives an error. To fix this, you need to place an explicit call to the super class constructor as the first line:
private AbsRelFile(){
super("fileName");
}
Most probably, you'll have to define some suitable parameters for AbsRelFile constructor too which you can pass to super call.
On another note, constructors cannot be overridden. So it is wrong to say that you're overriding the Object class constructor. You're simply defining a constrcutor for AbsRelFile class.
Constructors, by default, call the default constructor of the super-class if you don't make a super constructor call yourself.
To avoid this, make a call to an actually-defined constructor of File.
Java automatically puts in a call to super() in your empty constructor, which is why you get the error.
The problem is that your AbsRelFile constructor is trying to call the no-args constructor of File. What you have written is equivalent to
private AbsRelFile() {
super();
}
You need to make sure that you explicitly invoke one of the File constructors that does exist. For example:
private AbsRelFile() {
super("dummy");
}
Obviously, you will need to figure out a safe / harmless / appropriate superclass constructor and arguments to use for your particular use-case. (I haven't a clue what an AbsRefFile is really supposed to be ... so I cannot advise on that.)
Aside - you don't "override" constructors. Constructors are never inherited in Java, so overriding simply doesn't apply here. Instead you declare constructors in the subclass, and have them chain to the appropriate constructors in the immediate superclass via an explicit super(...) call ... or the implicit one the Java inserts by default.
First of all, I hope your field "File f" is not related to trying to access the superclass, but something to do with 'Rel' or 'Abs'..
The other posters have correctly pointed out that your implicit default constructor (AbsRelfile()) will attempt to call super() - which does not exist. So the only solution is to make a constructor that passes down some valid arguments.
If you are attempting to 'wrap' the whole java.util.File class (like when making your own Exception) you should probably provide a wrapper for each of the original constructors. Modern IDEs like Eclipse should have this a right-click away.
Note that File does not require that the given filename exists, in particular it does not exist when you want to do operations like file.mkdir().
If you need an actual, temporary file to work with, you could always do something like:
public class AbsRelFile() {
public AbsRelFile() {
super(File.createTempFile("AbsRelFile", "tmp").getAbsolutePath());
}
}
.. but I'm puzzled as to why you want to subclass File in the first place.
To explain WHY in one line:
When you define a constructor with a parameter (as in the File class), Java compiler WILL NOT generate the default constructor for you.
I'm learning Java (2nd year IT student) and I'm having a little problem. With inheritance to be precise. Here's the code:
class Bazowa
{
public Bazowa(int i)
{
System.out.println("konstruktor bazowy 1");
}
public Bazowa(int j, int k)
{
System.out.println("konstruktor bazowy 2");
}
}
class Pochodna extends Bazowa
{
/* Pochodna()
{
System.out.println("konstruktor pochodny bez parametru");
} */
Pochodna(int i)
{
super(i);
System.out.println("konstruktor pochodny z parametrem");
}
}
So, the Pochodna class extends the Bazowa class, and my exercise is to make a superclass that has only constructors with parameters and a subclass that has both types (with and without).
When I comment the first constructor in Pochodna class, everything works fine, but I don't really know how to make it work without commenting that part. I guess that I have to somehow call the constructor from the first one, but don't have an idea how to do that.
Any help would be appreciated,
Paul
Your first constructor from Pochodna calls by default super(), a constructor which you do not have in Bazowa.
You should either call one of the base constructors with 1 or 2 params in Pochodna(), or create a constructor with no parameters in your base class.
EDIT: Since you said you are learning Java, I will add some extra explanations to my answer.
Every class must have a constructor, so when you do not declare one explicitly, the compiler does so for you, creating a default constructor with no parameters. This constructor won’t be added if YOU declare constructors explicitly.
In inheritance, the child class is a “specialization” of the parent. That means that the child class contains the attributes and behavior of the parent class and extends on them. But you do not declare the parent elements again (unless you really want to overwrite stuff). So, when you create an instance of the child, somehow the elements taken from the parent must also be initialized. For this you have the super(...) construct.
The first thing that must be in a child constructor is a call to super(...) so that the elements taken from the parent are properly initialized before the child tries to do something with them (you can also have a call to another of child’s constructor this(...) – in this case, the last child constructor in the calling chain will call super(...) ).
Because of this, the compiler will again add a default call to super() – with no parameters – for you when you do not do so yourself in the child.
In the first constructor of Pochodna, since you did not call super(i) or super(j, k) yourself, a call to super() was placed by default. But in the parent class you explicitly specified constructors, so the default was not created by the compiler. And from here the exception, you end up calling a constructor that does not exist.
Hope this makes it easier to learn Inheritance. Cheers.
You need to specify something like this:
Pochodna()
{
super(0);
}
The trick here is that since you specify a constructor for the superclass the compiler doesn't create a no-arg constructor for you. When you make your zero-arg constructor in the superclass it tries to call the no-arg constructor in the subclass and fails to find anything.
In short, calling another constructor (either in the superclass or in the same class) in your constructor is not optional. Either you specify another constructor explicitly or a call to the superclass' zero-arg constructor will get inserted.
Since the base class does not have a parameterless constructor, you will need to call a constructor explicitly using super, providing some kind of a default value.
For example:
Pochodna()
{
super(0);
System.out.println("konstruktor pochodny bez parametru");
}
Alternatively, you can create a protected parameterless constructor in the base class. It will not be directly accessible from the outside, but derived classes will be able to use it.
Other answers handle the call to the super constructor.
Note that you could also do this:
Pochodna() {
this(0);
System.out.println("konstruktor pochodny bez parametru");
}
which would call your other constructor for Pochodna. Just another option. Study the output to understand what is happening.
As the default constructor is not present in the parent, you have to call the other constructor in the child constructor:
Pochodna() {
super(10);
}
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.