Virtual tables and abstract in Java - java

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

Related

child class method's output not printing?

when I called printThread, why is it printing 0 and 3?
class Super {
Super() {
three();
}
void three() {
System.out.println("three");
}
}
class Child extends Super {
int three = (int) Math.PI; // That is, 3
void three() {
System.out.println(three);
}
public static void main(String[] args) {
Child t = new Child();
t.three();
}
}
ouput is 0 and 3
but it should be 3 and 3
When you call new SomeType(..) then at first new creates instance of SomeType class with fields set up to its default values (for int it is 0, for boolean false, for object references null).
Proper initialization of object is done later via constructor code. This is why code responsible for initializing fields is moved at start of each constructor (after super() call since code in subclasses often depends on supperclass settings). So
class Child extends Super {
int three = (int) Math.PI; // That is, 3
is compiled as
class Child extends Super {
int three = 0;//initialization to proper value is moved to constructors
// |
Child(){ // |
super(); // |
three = (int) Math.PI; //<--------------------+
}
...
}
Because super() is invoked before proper initialization of three field, its value is still set to 0.
Constructor of superclass invokes three(); method but since it was overridden in Child class, because of polymorphism, code of Child#three is invoked. Since that code is printing value of three and proper initialization didn't happen yet, you are seeing as first its default value 0 (set by new operator).
After constructor finished his job you called three(); second time via t.three();. At that point three is properly initialized to 3 (result of (int) Math.PI;) so you are seeing 3.
To avoid such problems don't use in constructors methods which can be overridden in subclass. Either use fields directly, or use private, final or static methods.
If you step through this, three() will always be the child class's method (your implementation in Super will never be called).
Also, the first call to three() in Super() will actually run before the rest of the constructor for Child, hence the reason that the first call is 0 (the child object's not fully initialized yet).

What happens if you call an overridden method using super in a constructor

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.

why doesn't my field get initialized to the value I gave it

I have following classes:
public abstract class AClass {
public AClass() {
aMethod();
}
abstract protected void aMethod();
}
public class SubClass extends AClass {
private int x = 5;
private static final int y = 6;
#Override
protected void aMethod() {
System.out.println("x: " + x + " | y: " + y);
}
}
public class Main {
public static void main(String[] args) {
new SubClass();
}
}
Running Main prints the following: x: 0 | y: 6
Why does 0 get printed for x?
The reason of the misbehaviour is a wrong initialization sequence:
new SubClass() executes AClass constructor
AClass constructor calls aMethod()
aMethod() shows x (which is 0 so far) and y which is 6 because of being static)
SubClass initialize its non-static fields, so x becomes 5.
To avoid surprizes, never call virtual methods (esp. overriden) in constructors
The static field is initialized as soon as the class is initialized (after loading). Now when you call
new SubClass() the following things happen.
Constructor of SubClass is called as the first statement of SubClass (implicitly)
Constructor of SuperClass is called. --> you are checking value of x here
Once SuperClass constructor's execution completes, then instance level fields of SubClass are initialized. So x will be initialized here.
Initialization order. aMethod() is called before the line private int x = 5
Playing round with code examples like this is a great way to learn the order in which things are executed. Try adding a static and non-static initialization block too.
The result is because the super class constructor is called before the members are initialized.
In your case the following sequence is executed:
Call to constructor SubClass
immediate call to constructor AClass
call of method aMethod()
initializing of members of SubClass
This is also the reason why you should not call any overrideable methods from a constructor as the called method may access the state of an object that is not fully initialized.
private static final int y = 6;
Value of y is 6 when the constructor calls aMethod(), because it is static and is initialized while class loading.
private int x = 5;
While this initialization is appended at the end of your constructor body. It means while aMethod is being executed, the variable x has still default value i.e 0.
Default constructor of SubClass would look like
SubClass() {
super();
//All instance initialization are performed here.
}
Because when you created an instance of the Subclass it invokes the constructor of its super class AClass, and at this point, x was not yet set that's why it gets the default value of 0.

Java: Inheriting constructor to the subclass

As i knew, constructors,Instance Initialization block are NOT inherited to the subclass, but below code inherits the super-class constructor, why it is calling?
Expected output is :
from cons 2
but its showing output like:
--IIB--
from cons 1
from cons 2
WHY? this output , *As i know "sub class should not inherit Constructor & IIB block"*
Please help me to make clear this concept.
public class X
{
{
System.out.println("--IIB--");
}
X()
{
System.out.println("from cons 1");
}
}
class Y extends X
{
Y()
{
System.out.print("from cons 2");
}
}
class Z
{
public static void main(String args[])
{
Y ob=new Y();
}
}
This is happening because this:
Y()
{
System.out.print("from cons 2");
}
actually becomes
Y()
{
super(); //Call to X's constructor made here even if you don't call it
System.out.print("from cons 2");
}
The reason for this is that every Y is also an instance of X. It's necessary to call that parent constructor first, before any of the child constructor executes, to guaranteee that the parent attributes are ready to go.
Edit: here's the example to show that "super class constructors are not inheriated by the subclass":
class A {
A(int intForA) {
//Do stuff...
}
}
class B extends A {
B() {
this(3); //Won't compile! A's constructor isn't inherited by B
}
}
Instead, we do this:
class B extends A {
B() {
super(3); //This compiles; we're calling A's constructor from B
}
}
"The Java compiler copies initializer blocks into every constructor."
- http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
"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."
- http://docs.oracle.com/javase/tutorial/java/IandI/super.html
When you call the sub class constructor, it internally calls the super class constructor using the super()(Note section in the linked page at the last) and in your case, the super class for Y is X. Also, the instance blocks are copied in the constructor and thus are executed when any of the constructors of that class are called.
From the init block docs
Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword:
{
// whatever code is needed for initialization goes here
}
The Java compiler copies initializer blocks into every constructor.
Thus the output in the below order.
--IIB-- - From the instance block which gets placed inside the constructor of X.
from cons 1 - when super() is called inside Y()
from cons 2 - the SOP in Y()
in you code Y extends X so ideally when you create Y class object it also create X class object. So its block gets execute first then constructor of X and then constructor of Y .
Hence you are getting output like that.

Problem in instance variable initialization

Heres some sample code,
class Base
{
private int val;
Base() {
val = lookup();
}
public int lookup() {
//Perform some lookup
// int num = someLookup();
return 5;
}
public int value() {
return val;
}
}
class Derived extends Base
{
private int num = 10;
public int lookup() {
return num;
}
}
class Test
{
public static void main(String args[]) {
Derived d = new Derived();
System.out.println("d.value() returns " + d.value());
}
}
output: d.value() returns 0 // I expected 10 as lookup() is overridden, but not 0! can someone clarify this?
The initialization of Derived's instance variables has not happened at the time its lookup method executes. How do I make sure the instance variables of Derived are initialized when its method is called?
Well for a start, that code doesn't compile due to the lack of someLookup method.
Anyway, asides from that I believe your issue is that your expections are invalid because of the way constructors are run hierarchically.
A superclass' constructor is always run before the subclass', and this includes initializers for the subclass' variables (which are really run as part of the constructor). So, when you create your instance of Derived, the following happens:
The Base constructor is invoked first.
lookup() is called, which uses the implementation in Derived.
num is returned, which is the default value at this point because Derived's constructor and initializers have not been run.
val is set to 0.
The Derived initializers and constructor are run - calling lookup from this point on will return 10.
In general, it's a bad idea to call a non-final method from a constructor for exactly this reason, and many static analysis tools will warn you against it. It's similar to letting object references leak during construction, you can end up with an instance that invalidates class-level invariants (in your case, Derived's num is "always" 10 yet it can be seen to be 0 at some points).
Edit: Note that for this particular case, without any additional code, you could resolve the issue by making num a constant:
class Derived extends Base
{
private static final int num = 10;
...
This would actually do what you want, because the static initializer is run when the class is loaded (which has to happen before the constructors are called). This does however assume that it's fine for:
a) all instances of the class to share the same num variable;
b) num never needs to change (if this is true then (a) is true automatically).
In the exact code you've given this is clearly the case, but I expect you may be omitting extra functionality for brevity.
I include this here for comparison and interest, not because it's a workaround to this "issue" in a general sense (because it's not).
The reason you are getting 0 returned is that the constructors Base is being called (and calling lookup in Derived) before 10 is assigned to num in Derived.
To put generally, the base constructor is called before the derived instance fields are initialised.
There are a lot of great answers already on why you can't access subclass fields while constructing the base class, but I think you asked for a how: a working solution for something like this:
public abstract class Animal {
public Animal() {
System.println(whoAmI());
}
public abstract String whoAmI();
}
public Lion() extends Animal {
private String iAmA = "Lion";
public Lion(){super();}
public String whoAmI() {return iAmA;}
}
The practical way is to introduce an init() method on the base class an call it from the subclass's constructor, like:
public abstract class Animal {
private boolean isInitialized = false;
public Animal() {}
void init() {
isInitialized = true;
System.out.println(whoAmI());
}
public abstract String whoAmI();
public void someBaseClassMethod() {
if (!isInitialized)
throw new RuntimeException("Baseclass has not been initialized");
// ...
}
}
public Lion() extends Animal {
private String iAmA = "Lion";
public Lion() {
super();
init();
}
public String whoAmI() {return iAmA;}
}
Only problem is, you can't force subclasses to call the init() method on the base class and the base class might not be properly initialized. But with a flag and some exceptions we can remind the programmer at runtime that he should have called init()...
It is generally a bad idea to call methods in a constructor that can be overriden in a subclass. In your example the following happens:
Derived constructor is called
Base constructor is called as its first action
Base constructor calls lookup
Derived constructor continues and initialies num to 10
Since the subclass constructor is not finished when the base constructor calls lookup, the object is not yet completely initialized and lookup returns the default value of the num field.
Let's take it slowly:
class Test
{
public static void main(String args[]) {
// 1
Derived d = new Derived();
// 2
System.out.println("d.value() returns " + d.value());
}
}
Step 1, you call the (default) constructor on Derived, before setting num = 10, it chains up to Base's constructor, which calls Derived's lookup method, but num has not been set, so val remains uninitialized.
Step 2, you call d.value(), which belongs to Base, and val is unset due to 1, and therefore you get 0 instead of 10.
You have overriden method lookup() in the Derived class, so when the Base constructor is called it calls the method from Derived which body is return num. At the time of Base initialization the num instance variable of the Derived is not yet initialized and is 0. That's why val is assigned to 0 in Base.
If I understood your intentions correctly, you should change the value method in Base to be:
public int value() {
return lookup();
}
The below piece of code is returing 0 (you would expect 10 by looking at the program) when the constructor makes a call to this. The simple reason is that num is not initialized yet and the parent class calls this method.
public int lookup() {
return num;
}

Categories

Resources