views:

104

answers:

4

GIVEN:

class A
{
    String s = "A";
}

class B extends A
{
    String s = "B";
}

public class C
{
    public static void main(String[] args){ new C().go();}
    void go()
    {
        A a = new B();
        System.out.println(a.s);
    }
}

Question:

What are the mechanics behind JVM when this code is run? How come a.s prints back as "A".

+4  A: 

Field references are not subject to polymorphism, so at compile time the compiler is referencing A's field because your local variable is of type A.

In other words, the field behavior is like the Java overloading behavior on methods, not the Java overriding behavior.

Yishai
Thank you for your answer. If you could I want to clarify from your response the following: [1] Is there a difference what "a" hold at run time and compile time. [2] At which point in the code does the actual overloading mechanism occurs?
Krolique
err, correction: [2] .... does the actual field "overloading" mechanism occurs? =)
Krolique
@Krolique, A doesn't actually hold anything at compile time (it is just a definition, it isn't executed code). The overloading occurs when you define a variable s in class B. At that point you have two fields with the same name in two different classes. The compiler is the one that determines which one you mean to reference in your code. It is not dynamic.
Yishai
Thank you, I think this clarifies things a whole lot!
Krolique
+1  A: 

This isn't polymorphism (as tagged).

Java has virtual methods, not virtual member variables - i.e. you don't override a property - you hide it.

Bozho
It's not a property, it's a field.
Wim Hollebrandse
and a member variable. the terminology isn't strict
Bozho
Thank you for your answer. I missed subtle difference between virtual (inherited?) methods and member.
Krolique
read the wikipedia article I linked to understand what virtual methods are
Bozho
+2  A: 

You probably expect fields to be overridden like method, with dynamic dispatch based on the runtime type of the object.

That's not how Java works. Fields are not overridden, they are hidden. That means an object of class B has two fields named "s", but which of them is accessed depends on the context.

As for why this is so: it wouldn't really make sense to override fields, since there is no useful way to make it work when the types are different, and simply no point when the type is the same (as you can just use the superclass field). Personally, I think it should simply be a compiler error.

Michael Borgwardt
Thank you for your answer. Just see if I have grasped the concept correctly. Context implies declared type?Lets say if it was possible to upcast and I did the following: B b = new A(); then in b.s should print "B"?
Krolique
Since that's not possible it's kinda pointless to argue what it "should" print, but yes, that's the basic idea.
Michael Borgwardt
Thank you, I think this clarifies things a whole lot!
Krolique
A: 

Although member variables are inherited from a base class, they are not invoked polymorphically (i.e dynamic invocation does not apply to member variables).

So, a.s will refer to the member in the base class and not the derived class.

Having said that, the code is not following OO principles. The members of a class need to be private/protected (not public or default) depending on the business use case and you need to provide public methods to get and set the values of the member.

java_geek
Thank you for answer. In all normal circumstances I would do as you have suggested.
Krolique