views:

106

answers:

3

Consider this:

class A  {
    int x =5;
}

class B extends A{
        int x =6;
    }
public class CovariantTest {

    public A getObject() {
        return new A();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        CovariantTest c1 = new SubCovariantTest();
        System.out.println(c1.getObject().x);
    }

}

class SubCovariantTest extends CovariantTest {
    public B getObject(){
        return new B();
    }
}

As far as I know, the JVM chooses a method based on the true type of its object. Here the true type is SubCovariantTest, which has defined an overriding method getObject.

The program prints 5, instead of 6. Why?

+10  A: 

The method is indeed chosen by the runtime type of the object. What is not chosen by the runtime type is the integer field x. Two copies of x exist for the B object, one for A.x and one for B.x. You are statically choosing the field from A class, as the compile-time type of the object returned by getObject is A. This fact can be verified by adding a method to A and B:

class A  {
    public String print() {
        return "A";
    }
}

class B extends A {
    public String print() {
        return "B";
    }
}

and changing the test expression to:

System.out.println(c1.getObject().print());
Mehrdad Afshari
You did a much better job of explaining it than me... Its actually kind of a tricky one to word...
LorenVS
+1  A: 

Unless I'm mistaken, methods are virtual in java by default, so you're overriding the method properly. Fields however (like 'x') are not virtual and can't be overriden. When you declare "int x" in B, you are actually creating a totally new variable.

Polymorphism doesn't go into effect for fields, so when you try and retrieve x on an object casted to type A, you will get 5, if the object is casted to type B, you will get 6.

LorenVS
+1  A: 

When fields in super and subclasses have the same names it is referred to as "hiding". Besides the problems mentioned in the question and answer there are other aspects which may give rise to subtle problems:

From http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html

Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.

Some compilers will warn against hiding variables

peter.murray.rust