I'm a beginner and currently reading inheritance and polymorphism. I'm having some confusion in terms of the keyword "extend" and how constructors are called. Here's the code:
public class Test {
public static void main(String[] args) {
new B();
}
}
class A {
int i = 7;
public A() {
System.out.println("i from A is " + i);
}
public void setI(int i) {
this.i = 2 * i;
}
}
class B extends A {
public B() {
setI(20);
System.out.println("i from B is " + i);
}
public void setI(int i) {
this.i = 3 * i;
}
}
I know that by calling B() in line 3, class A's constructor is invoked, and then B's is invoked (is that right?) and thus it displays "i from A is 7" and then "i from B is 60". But can someone explain the importance of this? Why is int i in B completely different from in i in A? Again, I'm having trouble following the "path" of the code after the line new B(). If someone could explain each step after B() is invoked, that would be much appreciated.
I'm having trouble following the "path" of the code after the line new
B(). If someone could explain each step after B() is invoked, that
would be much appreciated.
When calling new B(), the flow technically enters the constructor B() first. Constructors in Java always need to (eventually) chain to a higher constructor (recursively until the highest class, Object, is reached). Chaining is denoted by a super(...) or this(...) statement as the first statement of the constructor. If none is explicitly written, the parameterless super() is assumed. So, B() actually compiles as if it were written like this:
public B() {
super();
setI(20);
System.out.println("i from B is " + i);
}
Now you can clearly see that new B() calls B() which calls A() (which calls println and exits), then setI and finally println.
Why is int i in B completely different from in i in A?
The i is exactly the same field. The difference comes from the fact that you've invoked setI(20) between the two printouts, thus changing the value of i. If you remove the call to setI, you'll see that the value remains 7.
When you are creating your instance of B and you call the constructor B(), it will first call super(), which in your case will call A().
This prints i from A is 7, because 7 is your default that you are setting i to.
After super is called, it moves on to the next line, which is setI(20). This line sets the i in B to 60 because your setI(int i) method multiplies the parameter (20) by 3, then sets i to that value.
Then, you are printing i from B is 60 because i is now 60.
The Java language spec says
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.
This means that when you write new B(), the first thing that the constructor for B does is to call the constructor for A. After the constructor for A has set i to 7, the constructor for B invokes setI(20), which changes the value of i to 60. There's only one i - it's not different in A and in B. It has simply changed value between one println and the next.
A subclass must always call the constructor of its superclass via super() or by invoking another constructor using super and the arguments of that constructor.
If you don't add super() explicitly, Java will do it for you behind the scenes.
class B extends A {
}
Is the same as calling:
class B extends A {
public B() {
super();
}
}
Knowing that, it should be apparent that calling new B(); will call the B constructor, which then calls the A constructor before finishing.
When you call to new B(), VM calls implicity super(), then a new A() is writing 7, but in your setI you are overwriting the method, it is because you see 60.
Use anotation #Override is allways a good idea.
BR
Related
I thought that super(); means almost the same as we call the superclass constructor, but it doesnt.
class A {
A() {
foo();
}
void foo() {
System.out.print("A");
}
}
class B extends A {
void foo() {
System.out.print("B");
}
B() {
super();
super.foo();
}
}
When I call new B(); it prints BA why? I was debuging it and super() call constructor of A but it prints B(this is what Im not understanding), and why after this super.foo() prints A as it should. Can someone explain how does it works?
The reason it prints BA:
you call new B();
B constructor calls A constructor (your super() call)
A constructor calls foo
foo() is overridden in B, so it resolves to B.foo()
B.foo() prings "B"
B.foo() returns, and A constructor returns
B constructor moves to next call, which is to super.foo()
Because of the "super" qualification, this resovles to A.foo()
A.foo() prints "A"
The end
Why does it print "B" from A's call to foo()? Because foo() is an instance method, "this" is an instance of B, and B has a method with the same signature as A.foo, so this resolves to the subclass method B.foo. This is called virtual method resolution and is a fundamental concept of object-oriented programming. The terminology is that B.foo overrides A.foo.
Your program flow is as follows:
The constructor of B is called.
It calls the constructor of A with the super();. As an aside, that line is unnecessary and would be done automatically if left out.
The constructor of A calls foo() of B. The call foo(); is to the B version of foo() because the object is an instance of B, and the B version of foo() overrode the A version of foo(). So you get a 'B' printed.
The constructor of A returns to the constructor of B, which calls super.foo();. This calls the A version of foo() because you specifically told it to do so with the "super" prefix. So it prints an 'A'. (Note that this is not a call to a constructor, in case you were confused about that.)
The reference in one of the comments (What is virtual method calling in java?) explains more about this.
It's actually part of one interview question I got confused.
class A
{
public A()
{
System.out.println("A") ;
}
}
class B extends A
{
public B()
{
System.out.println("B") ;
}
}
A a1 = new B();
System.out.println() ;
A a2 = (A) new B() ;
So the question is what is the print out?
At first I thought it should print out like
B
A
B
A
But after I run at home, it gives
A
B
A
B
I understand it's inheritance and then upcasting B to A, and it's legal syntax as well, but why is A print before B?
why is A print before B?
Because the body of the superclass constructor is executed before the body of the subclass constructor, basically.
Think of your B() constructor as implicitly:
public B()
{
super(); // This invokes A's constructor
System.out.println("B") ;
}
The full details are in JLS 12.5. In particular:
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps.
The constructor of the parent class A is called before that of the subclass B. In other words, it is equivalent to:
public B() {
super();
System.out.println("B");
}
There is two classes Super1 and Sub1
Super1.class
public class Super1 {
Super1 (){
this.printThree();
}
public void printThree(){
System.out.println("Print Three");
}
}
Sub1.class
public class Sub1 extends Super1 {
Sub1 (){
super.printThree();
}
int three=(int) Math.PI;
public void printThree(){
System.out.println(three);
}
public static void main(String ...a){
new Sub1().printThree();
}
}
When I invoke the method printThree of class Sub1 I expected the output to be:
Print Three
3
Because Sub1 constructor calling the super.printThree();.
But I actually get
0
Print Three
3
I know 0 is default value of int but how it is happening ?
You're seeing the effects of three things:
Default super-constructor calls, and
Instance initializers relative to super calls, and
How overridden methods work
Your Sub1 constructor is really this:
Sub1(){
super(); // <== Default super() call, inserted by the compiler
three=(int) Math.PI; // <== Instance initializers are really inserted
// into constructors by the compiler
super.printThree();
}
(Surprising, I know, but it's true. Use javap -c YourClass to look. :-) )
The reason it looks like that is that the superclass must have a chance to initialize its part of the object before the subclass can initialize its part of the object. So you get this kind of interwoven effect.
And given that that's what Sub1 really looks like, let's walk through it:
The JVM creates the instance and sets all instance fields to their defaults (all bits off). So at this point, the three field exists, and has the value 0.
The JVM calls Sub1.
Sub1 immediately calls super() (Super1), which...
...calls printThree. Since printThree is overridden, even though the call to it is in the code for Super1, it's the overridden method (the one in Sub1) that gets called. This is part of how Java implements polymorphism. Since three's instance initializer hasn't been run yet, three contains 0, and that's what gets output.
Super1 returns.
Back in Sub1, the instance initializer code for three that the compiler inserted (relocated, really) runs and gives three a new value.
Sub1 calls printThree. Since three's instance initializer code has now run, printThree prints 3.
With regard to this instance initializer code getting moved into the constructor, you might be wondering: What if I have more than one constructor? Which one does the code get moved into? The answer is that the compiler duplicates the code into each constructor. (You can see that in javap -c, too.) (If you have a really complicated instance initializer, I wouldn't be surprised if the compiler effectively turned it into a method, but I haven't looked.)
It's a bit clearer if you do something really naughty and call a method during your instance init: (live copy)
class Super
{
public static void main (String[] args) {
new Sub();
}
Super() {
System.out.println("Super constructor");
this.printThree();
}
protected void printThree() {
System.out.println("Super's printThree");
}
}
class Sub extends Super
{
int three = this.initThree();
Sub() {
this.printThree();
}
private int initThree() {
System.out.println("Sub's initThree");
return 3;
}
protected void printThree() {
System.out.println("Sub's printThree: " + this.three);
}
}
Output:
Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3
Note where "Sub's initThree" came in that sequence.
When the instance is created, the Sub1 constructor is called.
The first instruction in any constructor is a call to the superclass constructor. If you don't have an explicit call, there will be an implicit call to the no-args constructor of Super1.
The no-args constructor is calling this.printThree(). This method is overridden in Sub1. Now, this part may be confusing, but even if the code is in the superclass, this.method() still refers to the overriding method.
So it's calling the printThree() in Sub1, which prints the uninitialized value of the variable three - 0.
Now that the superclass's constructor is done, it completes Sub1 constructor, which uses super.printThree(). Since it specifically says super, the method from Super1 is used rather than the overriding one. This prints the Print Three.
Now the Sub1 constructor is also done, and main calls the new instance's printThree(). Now three is already initialized, so you get the output 3.
While previous answers gave you clear answer to what is happening, they did not gave you any pointers on how to avoid your problems in the future, so I would also like to add my input on this.
If you are going to inherit, then you should make the super class constructor as "dumb" as possible. For example
public class Super{
private int a,b;
public Super(int a, int b) {
this.a = a;
this.b = b;
}
//all the methods operating on the data provided by constructor
}
and then having sub constructor like this
private int c,d;
public Sub(int a, int b) {
super(a,b);
c = a;
d = b;
}
Is perfectly fine and is going to give you minimal side-effects, while keeping the functionality of the parent class.
But having
public Super(){
method1();
method2();
}
and then having sub do this
public Sub(){
super.method1();
super.method2();
}
Is really asking for trouble and possible hard to track bugs. The less the object does during initialization, the better, because it gives the childs flexibility.
Managing inheritance is like being dumb manager vs clever manager. Dumb manager calls Tim and Tracy employee, because they are both employees, and their jobs as Accountant and HR manager are just tags. Clever manager knows Tim and Tracy are Accountant and Manager and does not care that much that they are basically just employees.
In an interview I was given the following code:
public abstract class Base {
public int x = 1;
public Base() {
foo();
}
public abstract void foo();
}
public class Derived extends Base {
int x = 2;
#Override
public void foo() {
System.out.println("Derived: "+x);
}
}
class Main {
public static void main(String... args) {
Base base = new Derived();
base.foo();
}
}
They asked:
What will be printed?
If we were using C++ I think the code should give a compilation error because when the Derived constructor is called first the constructor of the Base class is called. At this point the foo method doesn't exist.
In addition I know that first the inherited class constructor is called, before all the
variables is created.
However in Java we get:
Derived: 0
Derived: 2
Why?
I know that like in C++ Java inheritance is based always on virtual tables,
and the constructor of the Base class is called before the constructor of the Derived class.
This is the order in which the code is executed. More details follow.
main()
invokes Derived.<init>() (the implicit nullary constructor)
invokes Base.<init>()
sets Base.x to 1.
invokes Derived.foo()
prints Derived.x, which still has the default value of 0
sets Derived.x to 2.
invokes Derived.foo().
prints Derived.x, which is now 2.
To completely understand what is going on, there are several things you need to know.
Field Shadowing
Base's x and Derived's x are completely different fields which happen to have the same name. Derived.foo prints Derived.x, not Base.x, since the latter is "shadowed" by the former.
Implicit Constructors
Since Derived has no explicit constructor, the compiler generates an implicit zero-argument constructor. In Java, every constructor must call one superclass constructor (with the exception of Object, which has no superclass), which gives the superclass a chance to safely initialize its fields. A compiler-generated nullary constructor simply calls the nullary constructor of its superclass. (If the superclass has no nullary constructor, a compilation error is produced.)
So, Derived's implicit constructor looks like
public Derived() {
super();
}
Initializer Blocks and Field Definitions
Initializer blocks are combined in declaration order to form a big block of code which is inserted into all constructors. Specifically, it is inserted after the super() call but before the rest of the constructor. Initial value assignments in field definitions are treated just like initializer blocks.
So if we have
class Test {
{x=1;}
int x = 2;
{x=3;}
Test() {
x = 0;
}
}
This is equivalent to
class Test {
int x;
{
x = 1;
x = 2;
x = 3;
}
Test() {
x = 0;
}
}
And this is what the compiled constructor will actually look like:
Test() {
// implicit call to the superclass constructor, Object.<init>()
super();
// initializer blocks, in declaration order
x = 1
x = 2
x = 3
// the explicit constructor code
x = 0
}
Now let's return to Base and Derived. If we decompiled their constructors, we would see something like
public Base() {
super(); // Object.<init>()
x = 1; // assigns Base.x
foo();
}
public Derived() {
super(); // Base.<init>()
x = 2; // assigns Derived.x
}
Virtual Invocations
In Java, invocations of instance methods normally go through virtual method tables. (There are exceptions to this. Constructors, private methods, final methods, and methods of final classes cannot be overridden, so these methods can be invoked without going through a vtable. And super calls do not go through vtables, since they are inherently not polymorphic.)
Every object holds a pointer to a class handle, which contains a vtable. This pointer is set as soon as the object is allocated (with NEW) and before any constructors are called. So in Java, it is safe for constructors to make virtual method calls, and they will be properly directed to the target's implementation of the virtual method.
So when Base's constructor calls foo(), it invokes Derived.foo, which prints Derived.x. But Derived.x hasn't been assigned yet, so the default value of 0 is read and printed.
Obviously, only the derived class's foo() is called.
It prints 0 in the first time because it happens before assigning x = 2, which happens only in the constructor of Derived, after Base's initialization is complete. It prints 0 and not 1, because Derived.x is being accessed and not Base.x, and it was not initialized yet, and is still 0. The declaration of x in Derived hides the field in Base, so when Derived is printing x, it prints Derived.x.
EDIT: activation order when creating Derived(): [schematic]
1. create Base:
1.1. assign Base.x = 1
1.2. invoke foo()
1.2.1 print Derived: Derived.x //Derived.x was not initialized here yet!
2. assign Derived.x = 2
The second is trivial and expected [in my opinion at least].
I am making some revisions from the lecture slides and it says a constructor is executed in the following way:
If the constructor starts with this, recursively execute the indicated constructor, then go to step 4.
Invoke the explicitly or implicitly indicated superclass constructor (unless this class is java.lang.Object).
Initialise the fields of the object in the order in which they were declared in this class.
Execute the rest of the body of this constructor.
What I don't understand is that a constructor can never "start" with this, because even if it forms no class hierarchy/relationship then super() is inserted by default.
How would this fit in with the description above?
A constructor (for every class except java.lang.Object) has to start with either "super()", to call its superclass' constructor, or "this()", to call another constructor of the same class. If you don't include either of those in your constructor the compiler will insert a call to super(). It's fine for a constructor to start with a call to another constructor in the same class, as long as eventually a constructor in the class gets called that calls a superclass constructor.
I don't think you're right, or I don't understand the problem. From the Java Language Spec:
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 is implicitly assumed by the
compiler to begin with a superclass
constructor invocation "super();", an
invocation of the constructor of its
direct superclass that takes no
arguments.
As such a constructor can start with this(...) which calls another constructor of the same class. Only when a constructor is called which does not start with either this(...) or super(...), super() is called automatically.
What I would say is that after an object is constructed super(...) has been called (if the class is not java.lang.Object).
here a more or less practical example for using this(...)
public class Car {
private final int numberOfDoors;
public Car(int doors) {
numberOfDoors = doors;
}
public Car() {
this(4); // default is 4 doors, calls the constructor above
}
}
the first statement in constructor body should be this or super , if nothing is there compiler by defalt keeps a super() keyword (with no argument).
so the Constructor body executes in this way:
Execution will happen on the basis of this or super keyword, then
it will execute all IIB's (as top down approach), then
it will execute all the statments kept by the programmer (like sop, initilization)
Class A{
A() {
this(10); //or super,....... execution statement 1
// executing IIB's, execution statement 2
System.out.println("from A()"); // execution statement 3
}
A(int i) {
System.out.println("from A(int)");
}
{
System.out.println("from IIB-1");
}
public static void main(String[] args){
A a = new A(); //calling constructor A()
System.out.println("from main");
}
{
System.out.println("from IIB-2");
}
}
Output:
from IIB-1
from IIB-2
from A(int)
from A()
from main
In Java, when you instantiate any object with new like C c = new C(); it delegate its super class constructor to create it first.
So in your case new C() --> Delegates to --> B() --> Delegates to A()
So execution flow is as below:
1) A() will Prints : 2
2) B() will calls B(1 ) prints 3 and control return to B() constructor
3) B() will prints : 4
4) C() will prints : 6
I hope it is now clear