Java subclass constructor inherited member - java

I have a question as to why does this piece of code, when executed, prints out the value 0. I don't exactly understand what happens in the SubClass constructor, and why is it that when I erase the overridden method implicitValue, it prints out 10. Does the SubClass constructor make use of the SuperClass constructor?
Thank you.
class SuperClass {
protected int superClassValue;
public SuperClass() {
superClassValue = implicitValue();
}
public int implicitValue() {
return 10;
}
public int getValue() {
return superClassValue;
}
}
class SubClass extends SuperClass {
private int subClassValue;
public SubClass() {
subClassValue = 20;
}
public int implicitValue() {
return subClassValue;
}
}
class Example {
public static void main(String argv[]) {
SubClass ss = new SubClass();
System.out.println("The value is " + ss.getValue());
}
}

TL;DR
Problem is that implicitValue from SubClass is used by superclass implicit SuperClass constructor (super()) via implicitValue() method, before subClassValue = 20; will be executed in SubClass constructor, so it returns default value of subClassValue which for int field is 0.
Does the SubClass constructor make use of the SuperClass constructor?
Yes, subclass constructor at start always invokes superclass constructor, so code
public SubClass() {
subClassValue = 20;
}
is same as
public SubClass() {
super();//superclass constructor
subClassValue = 20;
}
But lets take a look at your code. You are printing result of getVlaue() method which exists in your superclass
public int getValue() {
return superClassValue;
}
As you see it returns value of superClassValue. Before you invoke getVlaue() you are creating ss instance, so you are invoking code
super();//superclass constructor
subClassValue = 20;
which means you are invoking constructor of superclass which looks like
public SuperClass() {
superClassValue = implicitValue();
}
so this.superClassValue is initialized with returned value of implicitValue() method, but because of dynamic binding (late binding) JVM will try to search for implementation of this method starting from actual class of this which is SubClass, and since this class has its own overridden version it will be invoked
public int implicitValue() {
return subClassValue;
}
but subClassValue wasn't set to anything yet
super();// <-- we are still here
subClassValue = 20;// this line was not executed yet
so subClassValue still has its default value 0, which means that
superClassValue = implicitValue(); //will be initialized with 0;
so
public int getValue() {
return superClassValue;
}
will return 0.

In your case: SuperClass constructor will be called by default.
Logic for new SubClass().
It will call the constructor of the SuperClass first. When the constructor of the SuperClass is being called - A value return from the implicitValue() will be assigned to the variable superClassValue - The method implicitValue() being called is the method Of the SubClass (NOT the implicitValue() of SupperClass as you thought - Polymorphism feature of OOP).
When the implicitValue() of the SubClass is being called, the field subClassValue is not initialized yet so the field subClassValue still be ZERO. That is the reason you see Zero in the output.
When you remove override the implicitValue from the SubClass. the implicitValue() being called is the implicitValue() of the SupperClass --> This is why you see 10 in the output.

Yes, the subclass constructor implicitly calls the superclass constructor if such a call is not explicitly given. But it prints 0 because of the fact that the implicitValue method is overridden in SubClass.
The superclass constructor is called. Here, the SuperClass part of the object is created. All variables are initialized. Because there is no explicit value given, the compiler gives superClassValue the default value, 0. The superclass constructor then calls implicitValue(), which calls the subclass's method. This method returns superClassValue, which was initialized to 0. This value is explicitly assigned back to superClassValue.
The subclass initializes its subClassValue to 10.
The getValue() method is called, and it returns superClassValue, which is 0. The value is 0 is printed.
If you were to remove the implicitValue method in SubClass, then it would inherit SuperClass's version of the method, which returns 10.
If you were to modify the implicitValue method in SubClass to return 5, then it would initialize superClassValue to 5, and it would print The value is 5.

It sounds like something is wrong with your Override method or subclass. Because it sounds like when it is implements a variable the value is not getting instantiated so it is defaulting to 0 and then when you remove it the super class takes over resulting in you getting the value 10.

Related

Why constructor is not invoked when we use this keyword in Java?

'this'keyword refers to the instance of current class. So during the creation of instance of the class default constructor of the class must be called right? Like in this example.
Please do help me with this as I didn't found the answer to this question anywhere.
class Foo
{
int x = 100;
Foo obj = this;//Does it creates new instance of class or refers to calling object
Foo()
{
System.out.println("Constructor called");
}
Foo(int x)
{
this.x = x;// Why default constructor not invoked ?
}
void print()
{
System.out.println(x);
}
Foo ret()
{
return obj;
}
}
public class Main {
public static void main(String[] args) {
Foo obj = new Foo(10);
obj.print(); //prints 10
Foo xyz = obj.ret();
xyz.print(); //Also prints 10
}
}
Why default constructor not invoked ?
A constructor which doesn't explicitly invoke another constructor will invoke super() - the no-arg constructor of the superclass. This may not exist (and would result in a compiler error if not), but does in the case of Object.
From JLS 8.8.7:
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() isn't invoked because it's assumed that This(int) is capable of fully initializing the This instance. In general, This() and This(int) might do conflicting (or duplicative) things, so you wouldn't want to always invoke This() from This(int).
If you want this() to be invoked, invoke it.
//Does it creates new instance of class or refers to calling object
If it created a new instance of the class, that would create a new instance, which has a field that would be initialized to a new instance of the class. That, in turn, would have a field that would be initialized to a new instance of the class... You'd get a StackOverflowError
It refers to the current instance.
You didn't use the default constructor to initialise the object.
You used the constructor
Foo obj = new Foo(10);
Which would initialise the object using the method
Foo(int x)
{
this.x = x;
}
Your code Foo obj = this; refers the instance created when Foo obj = new Foo(10); is executed. In simple words both the variables named obj inside and outside the class hold the same instance that is why you are able to print 10 in both the cases. Write this(); method inside the parameterized constructor to invoke the default constructor of Foo class. Remember it will not create another instance though.

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.

Virtual tables and abstract in 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].

question on the output of a java snippet

The following snippet gives output as
Sup.field=0, Sup.getField()=1
I do not understand why Sup.getField() does not get 0 instead?
class Super {
public int field = 0;
public int getField(){return field;}
}
class Sub extends Super {
public int field = 1;
public int getField() {return field;}
public int get SuperField() { return super.field;}
}
public class FieldAccess{
public static void main(String[] args){
Super Sup = new Sub();
System.out.println("Sup.field ="+Sup.field + ",Sup.getField()"+Sup.getField());
}
}
Instance variables are not overridden ..they are merely hidden. Referring to the super.field refers to the actual field in the super class based on reference.
Methods are overridden and the call is made based on the object type at runtime.
All methods in java are virtual (c# term) or polymorphic by default and that's what you are seeing (the class fields are not).
When you call sup.field, it accesses field field in class Super but when you call getField() it calls the getField() method in class Sub because the instance is of type Sub.
This page has a good definition and some examples of polymorphism.
This is because,
Super Sup = new Sub();
This means that the object holds instance of the derived class object. That means, in the object memory the value of field is 1 and not 0.
So, when you run
Sup.getfield()
it runs the method of the derived class which resides in the memory that is tagged as memory for the Super class.
So, Its the difference in what it is and what it seems like.
What you are witnessing is the effect of method overriding (not to be confused with method overloading).
Even though the reference type is of type Super(), the actual method to call is resolved when the program is executing (runtime polymorphism), and because the getField() method is overridden by the subclass, that is what gets called and hence returns the value in the subtype. If you want 0 in both cases, change your instantiation to Super Sup = new Sub();

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