Reputation: 49665
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.
Upvotes: 5
Views: 8016
Reputation: 1581
However :
If you have a method that returns parent class A object, it can return any object type a class that extends it (Example of factory) . Now if this method returns a sub class B object and if you do not cast it to be a B, all its attributes will be the parent attributes . If you cast it to B then its attributes will be A and B attributes .
class A {
int a1,a2;
public A(){}
public static A getInstance () {
return new B() ;
}
}
class B {
int b1,b2;
public B() {}
}
class Test{
public static void main (String [] args) {
A theA = A.getInstance() ; //here theA has only a1,a2 as attributes
B theB = (B)theA // here theB has b1,a2 and a1,a2 as attributes
}
}
Upvotes: 0
Reputation: 3231
Declaring the variable "var" in both classes, actually creates two fields in memory.
An instance of "Porsche" will have two "var" fields in memory, one of the "Porsche" class and one of the super class "Automobile". The super class's "var" field is hidden when you refer to "var" from a known "Porsche" instance. If you cast this instance to "Automobile" and reference the "var" field, you reference the "Automobile"'s var field.
There is no overriding in fields. New fields with the same name overshadow the super class's fields.
To get the expected result you shouldn't declare a "var" field in the "Porsche" class at all.
Upvotes: 1
Reputation: 49311
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.
Upvotes: 2
Reputation: 20091
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.
Upvotes: 5
Reputation:
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.
Upvotes: 17