I am studying overriding member functions in JAVA and thought about experimenting with overriding member variables.
So, I defined classes
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
The output is:
1
I am class A
1
I am class B
I am not able to understand why when aRef is set to b intVal is still of class A?
There is no polymorphism for fields in Java.
Variables
decision happens at a compile time so always Base Class variables (not child’s inherited variables) will be accessed.So whenever upcasting happens always remember
1) Base Class variables will be accessed.
2) Sub Class methods(overridden methods if overriding happened else inherited methods as it is from parent) will be called.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
Variables are not polymorphic in Java; they do not override one another.
Answers from Oliver Charlesworth and Marko Topolnik are correct, I would like to elaborate a little bit more on the why part of the question:
In Java class members are accessed according the type of the reference and not the type of the actual object. For the same reason, if you had a
someOtherMethodInB()
in classB
, you wouldn't be able to access it fromaRef
afteraRef = b
is run. Identifiers (ie class, variable, etc names) are resolved at compile time and thus the compiler relies on the reference type to do this.Now in your example, when running
System.out.println(aRef.intVal);
it prints the value ofintVal
defined inA
because this is the type of the reference you use to access it. The compiler sees thataRef
is of typeA
and that's theintVal
it will access. Don't forget that you have both fields in the instances ofB
. JLS also has an example similar to yours, "15.11.1-1. Static Binding for Field Access" if you want to take a look.But why do methods behave differently? The answer is that for methods, Java uses late binding. That means that at compile time, it finds the most suitable method to search for during the runtime. The search involves the case of the method being overridden in some class.
OverRiding Concept in Java Functions will override depends on object type and variables will accessed on reference type.
For e.g.:
Here
parent
is a reference of Parent class but holds an object of Child Class so that's why Child class function will be called in that case.Here
child
holds an object of Child Class, so the Child class function will be called.Here
parent
holds the object of Parent Class, so the Parent class function will be called.When you trying to access the variable, it depends on the reference type object, not the object type.
For e.g.:
The reference type is Parent so the Parent class variable is accessed, not the Child class variable.
Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.
Here the reference type is Parent, so Parent class variable is accessed.
When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now actually have both properties. You can access the one from the superclass with
super.var
or((SuperClass)this).var
. The variables don't even have to be of the same type; they are just two variables sharing a name, much like two overloaded methods.