class A {
int a;
int b;
A(int i,int z) {
a = i;
}
void abc() {
System.out.println("a is " + a);
System.out.println("b is " + b);
}
}
class B extends A {
int a = 55;
int b = 66;
B() {
super(14,13);
super.b = 99;
}
}
public class test {
public static void main(String[] argue) {
B obj = new B();
obj.abc();
}
}
output:
a is 14
b is 99
I would refer to the above code for my questions. I don’t have some basic OOP concepts vivid. Please clear my doubts regarding the following queries:
- What actually happened when class B extended A? Was the code from A copied pasted in B, each variable defined in A is now defined in B also and each method definition in A is now also in B?
- As a class is just a template it lists the attributes that the object will have and the memory will only be allocated for each variable definition in a class when its object is made. Now if you say that when class B extended A the code from class A was not copied pasted into B i.e. the variables (int a, int b) originally defined in A their definitions are not pasted in class B.When the object of class B is created it allocates memory for variables ‘a’ and ‘b’ in class B, not of class A as their definition is not copied pasted in B. How can class B use the super class variables ‘a’ and ‘b’ even though the super class wasn’t instantiated i.e. ‘a’ and ‘b’ don’t exist in memory as class just defines a template. Does the compiler allocate separate memory portion for ‘a’ and ‘b’ on special consideration for class B as it extended class A? What about the method defined in the class A?
-
I was expecting obj.abc() (the last statement in the main method) to print:
a is 55 b is 66
as the method abc() was originally defined in class A and now class B inherits A so it inherited abc(). So if I called abc() with a reference of class B’s object it should have printed the values of ‘a’ and ‘b’ in class B i.e.
a is 55 b is 66
6
The output you describe does not correspond to the code you posted. It actually prints
a is 14
b is 99
I’ll get to why that’s happening later. But first, I’ll rewrite your code into a form that demonstrates the relationships typically found in inheritance:
public class A {
int a;
int b;
A(int i, int z) {
a = i;
b = z;
}
void abc() {
System.out.println("a is " + a);
System.out.println("b is " + b);
}
}
public class B extends A {
B() {
super(14, 13);
}
}
public static void main(String[] argv) throws Exception {
B obj = new B();
obj.abc();
}
Which gives the output
a is 14
b is 13
This is inheritance in its simplest form, and has the following characteristics:
- An instance of
B
contains two member variables,a
andb
. These variables are defined by classA
. - When you invoke the method
abc()
on an instance ofB
, the JRE determines that the method is actually defined in classA
. This is known as dynamic dispatch, and is one of the key features of inheritance.
Now a modification:
public class B extends A {
B() {
super(14, 13);
}
@Override
void abc() {
System.out.println("b is " + b);
System.out.println("a is " + a);
}
}
Here I’ve overridden the method abc()
in class B
. When the JVM examines the class, it determines that B
has defined the method, so invokes that implementation and does not look for an implementation in A
.
Because B
extends A
, and the member variables a
and b
are not declared private
by A
, B
has access to those variables. The output is:
b is 13
a is 14
Another modification:
public class B extends A {
B() {
super(14, 13);
super.b = 99;
}
@Override
void abc() {
System.out.println("b is " + b);
System.out.println("a is " + a);
}
}
This highlights the construction chain. In an inheritance hierarchy, a class’ constructor must call a superclass’ constructor. So here, B()
explicitly calls A(int,int)
, which implicitly calls Object()
.
The ordering is important: immediately after the call super(14,13)
, the value of member variable b
is 13. However, the B()
constructor changes that value, so the program prints
b is 99
a is 14
I left the assignment as super.b = 99
, but in this case it could also have been just been b = 99
, because class B
has access to the variable defined by A
. However, this form becomes important in the next revision.
Let’s bring this program one step closer to your original:
public class B extends A {
int a = 55;
int b = 72;
B() {
super(14, 13);
super.b = 99;
}
@Override
void abc() {
System.out.println("b is " + b);
System.out.println("a is " + a);
}
}
In this case I’m redefining the variables a
and b
within class B
. These definitions shadow the definitions from class A
. This is where it gets tricky — and why, in production code, shadowing is a code smell.
- There are now four variables in the class instance. Two are defined by class
A
, and two are defined by classB
. - The code in class
B
will ignore the variables defined byA
- Unless you explicitly prefix the variable reference with
super
So, after construction, here are the four variables:
a
, defined byA
, with the value 14b
, defined byA
, with the value 99a
, defined byB
, with the value 55b
, defined byB
, with the value 72
Note that the variable b
defined by A
was explicitly changed by B
‘s constructor, after it was assigned by A
‘s constructor, because B
‘s constructor referred to it with super
.
However, the definition of method abc()
in B
doesn’t prefix those variables with super
, so it will print the values of the variables defined by B
:
b is 72
a is 55
Last step: I remove the definition of function abc()
from class B
.
public class B extends A {
int a = 55;
int b = 72;
B() {
super(14, 13);
super.b = 99;
}
}
Now the JRE again invokes the function defined in A
. However, this implementation only has access to the two variables that are also defined by A
; it has no knowledge of the two variables defined by B
even though they exist within the object instance. So the output is
a is 14
b is 99
Why isn’t b
13
? Because the constructor for B
explicitly referenced the variable defined by A
.
Anyone who feels the need to add references to specs should feel free to do so; I don’t think they’re necessary.
1