views:

594

answers:

4

Hello,

I have a question about inheritance and casting in Java. I have the following two example classes and a test class, and I state my question after the classes:

public class Automobile {
    public int var;

    public Automobile () {
     var = 1;
    }

    public String toString () {
     return "AUTOMOBILE: " + var;
    }
}


public class Porsche extends Automobile {
    public int var;

    public Porsche () {
     var = 2;
    }

    public String toString () {
     return "PORSCHE: " + var;
    }
}

public class Test {
    public static void main (String [] args) {
     Porsche p = new Porsche();
     Automobile a = new Automobile();

     System.out.println ("(Automobile) p = " + (Automobile)p);

     System.out.println ("(Automobile) p.var = " + ((Automobile)p).var); 
    }
}

The output is:

(Automobile) p = PORSCHE: 2

(Automobile) p.var = 1

I don't understand why in the second statement we have 1. Shouldn't it be 2? Because after I cast p to Automobile in the first statement I still get PORSCHE: 2 as the representation of p - I understand this in the following way: nevertheless I have casted p to Automobile p keeps its "original nature" - p is an object of class Porsche, but because Porsche extends Automobile, we could say that p is also an Automobile. And therefore when we cast it explicitly to Automobile, it continues using its methods - in our case the method toString() defined in Porsche. On the other hand, if what I write is correct, then the second print statement should give 2 and not 1. Now this seems as a contradiction to me, but since this works in Java, it seems that I don't understand what's going on during the casting and the inheritance process. Therefore I am asking for a comment. Thanks you in advance.

+13  A: 

I believe you can't actually override variables in Java. The subclass actually 'hides' the variable var.

When you cast to Automobile, you're getting the superclass' version of the var variable. However, the toString() method is still looking at the instance's version of the var variable.

If you removed the public int var from the Porsche subclass it should work as expected.

It should be noted that it's not good practice to use public instance variables, you should always create getters / setters to have proper encapsulation.

Phill Sacre
Congratulations for passing 4k
jamesh
+4  A: 

Shadowing of the variable var.

Your Porche.var is a different variable than the Automobile.var.

The Porsche.toString() method uses the Porsche.var, whereas the cast tells the compiler to use the Automobile version.

jamesh
+1  A: 

Access to fields is not polymorphic - it depends only on the compile time type of the expression.

The expression ((Automobile)p) has compile time type Automobile, so its fields are used.

Pete Kirkham
A: 

This is essentially a duplicate of this question.

starblue