77

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?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Kalyan Raghu
  • 1,005
  • 1
  • 10
  • 19
  • possible duplicate of [Slight confusion regarding overriding where variables are concerned](http://stackoverflow.com/questions/12589274/slight-confusion-regarding-overriding-where-variables-are-concerned) – rob mayoff Jun 05 '13 at 19:02
  • I think this is not the same question, since the other one mixes several features of the language, while this one is purely about variables not being polymorphic – Vic Seedoubleyew Aug 09 '16 at 10:42
  • @Vic Seedoubleyew But it seems to me like a duplicate to [this question](http://stackoverflow.com/q/7794621/1303323) – Stelios Adamantidis Nov 22 '16 at 22:03
  • 1
    Possible duplicate of [Hiding instance variables of a class](https://stackoverflow.com/questions/7794621/hiding-instance-variables-of-a-class) – RBz Oct 23 '18 at 14:13

13 Answers13

98

When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now 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.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
71

Variables are not polymorphic in Java; they do not override one another.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 1
    So, as a variable is not overridden, no run time resolution is done for them, hence in the inheritance chain the variable value of the reference class is used when accessed instead of the object type. I verified it with extending the classes further and using an intermediate reference type. Thanks for the reply. – Kalyan Raghu May 23 '12 at 15:58
19

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.

Ankur Singhal
  • 26,012
  • 16
  • 82
  • 116
16

Variables are resolved compile-time, methods run-time. The aRef is of type A, therefore aRef.Intvalue is compile-time resolved to 1.

Rostislav Matl
  • 4,294
  • 4
  • 29
  • 53
4

OverRiding Concept in Java Functions will override depends on object type and variables will accessed on reference type.

  1. Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.

For e.g.:

Parent parent=new Child();
parent.behaviour();

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.

Child child=new Child();
child.behaviour();

Here child holds an object of Child Class, so the Child class function will be called.

Parent parent=new Parent();
parent.behaviour();

Here parent holds the object of Parent Class, so the Parent class function will be called.

  1. Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.

When you trying to access the variable, it depends on the reference type object, not the object type.

For e.g.:

Parent parent=new Child();
System.out.println(parent.state);

The reference type is Parent so the Parent class variable is accessed, not the Child class variable.

Child child=new Child();
System.out.println(child.state);

Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.

Parent parent=new Parent();
System.out.println(parent.state);

Here the reference type is Parent, so Parent class variable is accessed.

Aman Goyal
  • 409
  • 5
  • 8
  • 1
    Welcome to SO. Please do not format your whole answer as code. Highlight the code as code and the text as text. Thanks – Neuron Apr 01 '18 at 14:38
3

From JLS Java SE 7 Edition §15.11.1:

This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.

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 class B, you wouldn't be able to access it from aRef after aRef = 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 of intVal defined in A because this is the type of the reference you use to access it. The compiler sees that aRef is of type A and that's the intVal it will access. Don't forget that you have both fields in the instances of B. 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.

Community
  • 1
  • 1
Stelios Adamantidis
  • 1,866
  • 21
  • 36
2

I hope this can help:

public class B extends A {
//  public int intVal = 2;

    public B() {
        super();
        super.intVal = 2;
    }

    public void identifyClass() {
        System.out.println("I am class B");
    }
}

So overriding variable of base class is not possible, but base class variable value can be set (changed) from constructor of inherited class.

MilanG
  • 6,994
  • 2
  • 35
  • 64
  • 1
    Welcome to Stack Overflow! Generally, answers are much more helpful if they include an explanation of what the code is intended to do, and why that solves the problem without introducing others. – Tim Diekmann May 25 '18 at 03:02
2

This is called variable hiding. When you assign aRef = b; , aRef has two intVal, 1 is named just intVal another is hidden under A.intVal (see debugger screenshot), Because your variable is of type class A , even when you print just intVal java intelligently picks up A.intVal.

Answer 1: One way of accessing child class's intVal is System.out.println((B)aRef.intVal);

Answer 2: Another way of doing it is Java Reflection because when you use reflection java cant intelligently pickup hidden A.intVal based on Class type, it has to pick up the variable name given as string -

import java.lang.reflect.Field;

class A{
    public int intVal = 1;
    public void identifyClass()
    {
        System.out.println("I am class A");
    }
}

class B extends A
{
    public int intVal = 2;
    public void identifyClass()
    {
        System.out.println("I am class B");
    }
}

public class Main
{
    public static void main(String [] args) throws Exception
    {
        A a = new A();
        B b = new B();
        A aRef;
        aRef = a;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
        aRef = b;
        Field xField = aRef.getClass().getField("intVal");
        System.out.println(xField.get(aRef));
        aRef.identifyClass();
    }
}

Output -

1
I am class A
2
I am class B

enter image description here

sapy
  • 8,952
  • 7
  • 49
  • 60
0

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.

Community
  • 1
  • 1
  • I didn't get the first point. We can always access any non private member variables of a super class in a subclass. – Kalyan Raghu May 23 '12 at 16:34
0

Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.

If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.

dharam
  • 7,882
  • 15
  • 65
  • 93
  • In the debug mode I see that both b and aRef have both the intVal s whereas as per your comment I expected that only object b will have both the values. Is it because the debugger behaves in a different way than the JVM? – Kalyan Raghu May 23 '12 at 16:05
  • I guess there was a misunderstanding. Till the time u didn't assign b to aRef, it had only one intVal. When you assigned b to aRef, now it is pointing to an object of type B hence two intVals. – dharam May 23 '12 at 16:09
0

It is because when you assign b to aRef, it is resolved, leading aRef to just be of class A. This means that aRef does not have access to any of class B's fields or methods. If you call for intVal instead by using b.intVal, you will get 2.

-2

Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.

and in inheritance only method overrides so that it can affects only it's property.

Greesh Kumar
  • 1,847
  • 3
  • 27
  • 44
-2

As Many users have already pointed out, this is not polymorphism. Polymorphism only applies to methods(functions).

Now as to why the value of the intVal of class A is printed, this happens because as you can see the reference aRef is of type A.

I can see why you are confused by it. By the same procedure you have accessed the overridden methods for ex. the method identifyClass() but the not the variables which directly proves the first line that I have written .

Now in order to access the variable you can do ((Superclass)c).var

Note here that the Superclass can be many levels up for example A<-B<-C. That is C extends B and B extends A. If you wanted the value of var of A then you could have done ((A)c).var .

EDIT: as one of the users have pointed out this 'trick' does not apply to static methods, because they are static.

  • polymorphism does not apply to class methods – Shamshirsaz.Navid Oct 26 '20 at 08:48
  • First I have edited my response thanks for pointing it out. Second class methods are better called static methods. And finally, next time when you think of just plain downvoting please let the user first know what mistake he/she has made and downvote if not corrected. This is my first answer and now I can imagine why many people refrain from answering . Thanks a lot for the encouragement. – Achal_Jain Oct 27 '20 at 13:30