I'm having trouble understanding the concept of using constructors with subclasses.
Here is the parent class:
public class A
{
public A()
{
System.out.println("The default constructor of A is invoked");
}
}
The child class:
public class B extends A
{
public B(String s)
{
System.out.println(s);
}
}
And my main method:
public class C
{
public static void main (String[] args)
{
B b = new B("The constructor of B is invoked");
}
}
When I run C, the output I get is
The default constructor of A is invoked
The constructor of B is invoked
What I don't understand is why the message from class A is getting output. Because you pass in a string argument to the constructor of the B class, shouldn't it just print out s? In other words, shouldn't the output simply be:
The constructor of B is invoked
Thanks in advance, I really appreciate any help you guys can give.
From the docs
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.
So even though you've not explicitly called the super class constructor, the compiler inserts a statement called super() in the constructor of class B.
This is how the class B constructor would look post compilation.
public B(String s){
super(); // this is inserted by the compiler, if you hadn't done it yourself.
System.out.println(s);
}
After compilation class B -
public class B extends A{
public B(String s){
super();
System.out.println(s);
}
}
And why! logical answer is child can not be existed without parent, so parent is initialized fast then child.
Technically - if you do not explicitly invoke super class constructor compiler will do it for you. what exactly happened in your case.
A good experiment would be if you invoke the super class contructor explicitly which help you understand this more closely-
public class B extends A{
public B(String s){
System.out.println(s);
super(); // invoking super later
}
}
you get an compilation error -
error: call to super must be first statement in constructor
So In case you are explicitly invoking the super class constructor, then you have to invoke at the start of constructor which should be first statement.
The reason it does this is that B needs to have all the fields in A if B is indeed a subclass of A. Therefore, when you call the constructor
B b = new B("The constructor of B is invoked");
It calls the default constructor of A to initialize A's fields, thus B is actually logically doing
public class B extends A
{
public B(String s)
{
super();
System.out.println(s);
}
}
where super just calls A's default constructor. If the compiler did not do this, you would have uninitialized fields in B since it inherits from A!
Related
Why is the constructor in B required?
IntelliJ suggests to remove =null as it is redundant presumably because it is initialized through the given constructor in A.
However, this removal (which is presumably also performed by the compiler) then (presumably) requires the constructor in B.
Any other explanation?
public abstract class A {
private Object foo = null;
public A(Object foo){this.foo=foo;}
}
public class B extends A {
public B(Object foo){super(foo);}
}
Java does not have "constructor inheritance". The only way to initialize A is to pass the foo parameter to its constructor, and the only way to do this is to create a constructor for B that does so.
Note, however, that they don't have to have the same signature (like you have in the question) - B's constructor only needs to pass some parameter to A. E.g.:
public class B extends A {
public B() {
super("Arbitrary default passed to A");
}
public B(Object passedToA, Obejct notPassedToA) {
super(passedToA);
System.out.println("This argument was not passed to A():" + notPassedToA);
}
}
Why is the constructor in B required?
If the class B extends A, the class B must be instantiated in all possible ways as the class A can be and the class B can have additional ways to be instantiated. It means that class B is forced to have a constructor.
The only exemption can be in case of a no-arg constructor because the compiler makes it up with a default constructor i.e. if you put a no-arg constructor in the class A the child classes are not forced to have this.
In the book Java: The complete reference
// Demonstrate when constructors are called.
// Create a super class.
class A {
A() {
System.out.println("Inside A's constructor.");
}
}
// Create a subclass by extending class A.
class B extends A {
B() {
System.out.println("Inside B's constructor.");
}
}
// Create another subclass by extending B.
class C extends B {
C() {
System.out.println("Inside C's constructor.");
}
}
class CallingCons {
public static void main(String args[]) {
C c = new C();
}
}
Output:
Inside A’s constructor
Inside B’s constructor
Inside C’s constructor
It is demonstrating how the constructor of a subclass is called. But why are constructors of the super class called in the absence of a super() constructor.
Why did the Java Language designers consider it necessary to do so?
As others have pointed out, if you don't start your constructor with a super(...) call, the compiler will put in a call to super() for you.
As to the why, you have to start with remembering what a constructor is for in the first place: initializing the object. What does that mean, specifically? In practice, it means assigning values to the object's fields, and establishing invariants.
Without a call to super(), the B and A classes wouldn't have a chance to do that for whatever fields they contain. And you can't even have the C() constructor do it for them, if those fields are private, since private fields aren't accessible outside your class (not even your super class's fields are accessible). Even if you could, it wouldn't be a good idea; it would also break encapsulation. For instance, imagine having to change your code if a super class -- possibly a complex one whose internals you're not an expert in -- suddenly decided to change its implementation details.
To illustrate this, consider a very simple set of classes:
public class Super {
private final String name;
Super() {
name = "default";
}
public String name() {
return name.toUpperCase();
}
}
public class Sub extends Super {
public Sub() {
// don't do anything
}
}
When you instantiate Sub, it will start out by calling Super's constructor. If it didn't, the name field would be null (the default value for reference types). But the name() method doesn't check for null; it assumes that the reference is non-null, because the constructor establishes that invariant. So, in our pseudo-Java that doesn't call the super constructor, Super.name has to get a bit more complicated -- it has to check for name == null.
You can imagine that as the classes gain more fields, with more interesting invariants, this toy example can become more and more complicated. Forcing you to call the super constructor -- either explicitly or implicitly -- lets the authors of that super class establish their invariants, resulting in simpler, more maintainable code.
Every constructor calls its superclass constructor. super() call take place as the first line in the constructor. From javadoc:
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.
more here
Because it says so in the Java Language Specification.
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments.
Even it has a role with Abstract classes also. we can't initialize object of abstract class. But Child class of Abstract class calls the super() method by default. So abstract class constructor can initialize its instance variables.
for example:
public abstract class TestA {
private int a;
public TestA()
{
a=10;
}
public int displayA()
{
return a;
}
abstract void display();
}
public class TestB extends TestA{
#Override
void display() {
System.out.println("this is class B");
}
}
package Abstract;
public class TestMain {
public static void main(String[] args) {
TestA obj= new TestB();
System.out.println(obj.displayA());
}
}
Output is : 10
Here you can see, when we initiating object of class TestB , by default super constructor is calling and TestA's constructor is assigning the value of a. If super will not be called by default we can't assign instance variables of abstract class.
Inheritance is basically inheriting all the properties of your parent class. So if a sub class constructor is called, it should definitely and by default inherit all its parent class properties also. In the following code, all the properties of class A should be made available in class B also, so if I just call B's constructor, all the class A's properties(except private) are also initialized and made available, meaning B has inherited A's properties
class A {
protected int a;
A() {
a=12;
System.out.println("Inside A's constructor.");
}
}
class B extends A {
B() {
System.out.println("Inside B's constructor.");
System.out.println(a);
}
}
public class ConstructorInheritance {
public static void main(String args[]) {
B b=new B();
}
}
output:
Inside A's constructor.
Inside B's constructor.
12
Imagine class C accessing an unitialized variable of class B or A. Implicitly calling constructors of class B-->class A makes sure that you are always accessing initialized variables of inherited classes(A or B)
"The Java programming language" says "A constructor in subclass can initialize its individual state, however, as keeping contract, only super class knows how to initialize super class's state".
Thus, constructor of super class have to be called. There is sequence how the constructor processed:
Call super class constructor
Initialize fields with initializers and initialization blocks
Execute body of the constructor
For more details, have a look of the book to section "3.2".
In the following example:
class A {
private int a;
private int b;
private int c;
public A(int a, int b , int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
class B extends A {
public B() {
super(1,2,3);
}
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
You cannot call super() like this:
class B extends A {
super(1,2,3);
}
super() OR this() should be the first statement in a constructor. First correct this basic mistake of yours before going further. super() is used by default even if you don't explicitly use it.
class B extends A {
B (){
super(1,2,3);
}
}
This is the right way. Please Read about Constructors and Java language basics first before posting questions.
EDIT
I didn't notice that someone edited you question to add super(1,2,3) in a constructor, now answering your questions as follows:
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
No, by calling super(1,2,3) all you're doing is passing 3 integer values to the base class constructor public A(int a, int b , int c) After that you're assigning these values to the private instance variables of base class, you're not making a separate fields for class B, if thats what you asked, and No B class still can't access base class instance variables directly (by stating directly I mean by inheritance or making an instance, there are other ways like setters/getters etc)
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
No, if you don't use a constructor in B class which uses super(int, int, int) to match the arguments of base class constructor (int a, int b , int c) then your code won't even compile. The default constructor will call the no-args constructor of Base class, but since Base class has no default constructor you'll get compilation error!
First of all, the code you posted is not valid Java. It is important that you post working code, otherwise we can't be sure about what you are asking.
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
Assuming you put the statement in a constructor instead of at class level, which is illegal, then no, that will not automatically create fields in class B. It just calls the constructor in the superclass A that takes three int arguments and initializes the fields in the superclass part of the object.
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
Since there is no default (i.e. no-arguments) constructor in class A, you would get a compiler error - the compiler would complain that there is no appropriate constructor in class A.
Java only automatically adds a no-arguments constructor to a class if you do not specify a constructor at all in the class. Since class A already has a constructor, Java is not automatically going to add a no-arguments constructor.
First of all you need to understand one thing: private fields of a parent class ARE BEING INHERITED. The only thing is that if they are private in parent, then they cannot be accessed directly from the child class (the B class in your example). So in other words: not a single B class method can access those fields, but every A class method can access them. So for example its possible that there is a public/protected method inside A class that changes some of those fields and this method can be called from a child class (B).
Once you correct your class to the proper:
class B extends A {
public B() {
super(1,2,3);
}
}
...we can proceed to answer your actual questions.
The constructor of A does not create fields. The fields are created as part of creating of any A object, and are initialized by the constructor.
Those fields are created in B as well, but not because you called super(1,2,3) but because you extend A. As soon as an instance of B, which is an extended instance of A is created, those fields are there - but they are accessible only to methods that are declared in A itself and not in its descendents.
By calling super(1,2,3), you are initializing those private fields. They are still not accessible to B. The constructor of A is mediating between B and these private variables. If you had a method that prints those fields in A, and that method was not private, you could call it and it would print them with these values.
As for your second question, if you didn't call the super(1,2,3), Java would try to call the default constructor. However, for a class that has a constructor, there is no default constructor. The empty/nullary constructor only exists if you either declared it yourself, or if you didn't declare any constructor at all.
// The following two classes have a default constructor which will be called
// if any descendent doesn't call super(...)
class HasADefaultConstructor {
}
class AlsoHasADefaultConstructor {
AlsoHasADefaultConstructor() {
}
}
// But this one doesn't.
class DoesntHaveADefaultConstructor {
DoesntHaveADefaultConstructor( String a ) {
}
}
So you can't inherit private varibles, but you can access them if the parent class has the appropriate getters:
Run the example and you see the output is 'a is: 1'
Regarding the default constructor: In your example you have explicitly implemented
a constructor. So the implicit default constructor is not there any more
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
//access a
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
this is my program:
class A{
A(int a){
}
class B extends A{
B(){
}
}
}
when I compile I have an error:
C:\Users\Public\Documents\AB.java:6: error: constructor A in class A cannot be applied to given types;
B(){
^
required: int
found: no arguments
reason: actual and formal argument lists differ in length
and it fixed by this change in my code:
class A{
A(int a){
}
A(){
}
class B extends A{
B(){
}
}
}
but I don't understand why?
thanks for any help.
Since your A class declares a constructor
A(int a){
}
then any code that wants to instantiate A needs to do so with that constructor. Something like
A a = new A(42);
You also declare a child class, B. Since B is an A, in addition to its constructor, it must call the parent class' constructor. This is done implicitly by the compiler. Say you had
class A{
A(){
}
class B extends A{
B(){
// super(); injected by compiler
}
}
If you don't have a no-arg constructor, then the compiler doesn't know which constructor call to inject. You need to explicitly declare the super(...) call.
class A{
A(int a){
}
class B extends A{
B(){
super(42);
}
}
Think of it this way: you can't construct an A without the constructor call. When you construct a B, you are, through inheritance, also constructing an A, so you need that same constructor call.
You need to have a default constructor (no-argument) in A. The first implicit call of a constructor of any class is super(). But there is not super() method in the superclass. You can either explicitly call super(5) or some value, or create a default constructor in A:
A() {}
When instance of class B is created a default call to super() constructor with no parameters is made. Each class has a default constructor with no parameters, unless a different constructor is provided explicitly.
As you have explicitly provided class A with a constructor that takes one parameter, it no longer has default constructor with no params, so you need to define it.
Whenever we extend a class, by default it calls super() (it has no params). In your case , it dint get the matching A() , hence it resulted in compiler error.
Whenever u write this, what happens internally is :
class A
{
A(int a)
{
}
class B extends A
{
B()
{
//Internally compiler calls super()
super();//In your case, it dint get the matching constructor
}
}
}
class a
{
a(){System.out.println("A");}
}
class b extends a
{
b()
{
super();
System.out.println("B");}
}
class c extends b
{
c(){System.out.println("c");}
}
class last
{
public static void main(String aaa[])
{
c obj = new c();
}
}
Output Comes as:
A
B
C
Shouldn't it be:
A
A
B
C
because of super keyword
super(); is always there if you don't specify explicitly. Java only adds automatic call if you don't specify it explicitly.
So your code
B() {
super();
System.out.println("B");
}
is same as
B() {
System.out.println("B");
}
No. If you have a call to super within the constructor, the automatic call doesn't get added. The compiler only adds the automatic call if you leave yours out. So the super(); line in b is unnecessary, as that's exactly what the compiler will add for you (a call to the default constructor). That is, these two bits of source result in identical bytecode:
// This
class b {
b() {
}
}
// Results in the same bytecode as this
class b {
b() {
super();
}
}
The reason for being able to call the superclass constructor directly is for passing arguments to it, since the compiler will only ever add calls to the default constructor (and will complain if there isn't one on the superclass).
super(); is called once within any constructor through inheritance tree, either you do it explicitly or it is done implicitly. So you shouldn't expect that "A" will be printed twice.
This won't compile:
b()
{
super();
super();
System.out.println("B");
}
Error message: Constructor must be the first statement in a constructor.
It means that you are not allowed to call super() multiple times in a constructor.
If you create sub class of some other class, with extends keyword, then java compiler puts super() call as first line of your constructor (in case you have not done that yourself).
In your example, the class a extends (by default) java.lang.Object() and after compilation the first line is call super() which calls Object default constructor.
SO before code in sub class constructor is ran, the code in its super class constructor is ran.
Why is A not printed multiple times? Because Java compiler adds super() in the beginning of constructor only if you have not done that yourself. (For example, you might want to call super class constructor that takes in some parameters)
Hopefully that clarifies things a little bit.
package threaddemo;
public class NewClass {
NewClass() {
System.out.println("hello");
}
}
class Child extends NewClass {
Child() {
System.out.println("child");
}
public static void main(String []ar) {
Child c1=new Child();
}
}