I'm trying to understand the rationale for the last statement of my code being illegal in Java. See comment below.
public class Rectangle {
private int height;
private int width;
public Rectangle(int height, int width) {
this.height = height;
this.width = width;
}
}
class ColoredRectangle extends Rectangle {
private String color;
public ColoredRectangle(int height, int width, String color) {
super(height, width);
this.color = color;
}
public String getColor() {
return color;
}
public static void main(String[] args) {
ColoredRectangle blueRectangle = new ColoredRectangle(2, 4, "blue");
Rectangle sameObjectDifferentType = blueRectangle;
((ColoredRectangle) sameObjectDifferentType).getColor(); //Will compile
sameObjectDifferentType.getColor(); //Won't compile
}
}
I know that I shouldn't use this design, and instead use different constructors. I know that getColor()
is "not defined in Rectangle." Still, the way I think about this code is: sameObjectDifferentType is a reference to an object that is both a Rectangle and a ColoredRectangle, and therefore I should be able to access all of its members regardless if I declare the reference as Rectangle or ColoredRectangle. So... why is Java designed like this?
In this line, you are declaring that sameObjectDifferentType
is of a type Rectangle
Rectangle sameObjectDifferentType = blueRectangle;
In more real world examples, this would allow you to have several different types, that you would want to treat in the same way. The classic example is CurrentAccount
, CheckingAccount
, SavingsAccount
which all inherit from Account
.
Suppose your banking application had code to lookup an account and find out the account holder. That code would just deal with the abstract Account
types. It means that in the future when you introduce a StudentAccount
, providing it inherits from Account
you can use a StudentAccount
in all the places you currently deal with Account
s without changing code.
Suppose you had a FilledRectangle
and WireFrameRegtangle
in your example. You could have a calculateArea(Rectangle rect)
method that would apply to all Rectangles.
However, one trade off you make for this power and flexibility is that you lose the ability to directly deal with properties of the subclass when you declare an object to be of a super class type, so
sameObjectDifferentType.getColor(); //Won't compile
However, Java does give you a way to get back to the subclass as you have noted by casting:
((ColoredRectangle) sameObjectDifferentType).getColor(); //Will compile
You as a developer know that sameObjectDifferentType
is really a ColoredRectangle
under the hood so you are safe to make this cast.However if you did
((FilledRectangle) sameObjectDifferentType).getFillPattern();
You would end up with a run time ClassCastException
Hope this helps.