Reputation: 4845
This is a question in-regards to basic inheritance in Java with two classes.
We have two classes, with the first one being a Rectangle
:
private double length;
private double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
}
Next we have an extension class called Square
, which extends Rectangle
, so through super()
we know that it uses the constructor of the Rectangle
class.
private double side;
public Square(double side)
{
super(side, side);
this.side = side;
}
public void print()
{
System.out.println("I am a square of side " + side);
}
This is our main:
Square b = new Square(6.0);
Rectangle c = (Rectangle) b;
c.print();
We create a object of the type Square
, which would contain two side
variables the double
6.0
Next, we cast b
to Rectangle
c
, which is where my question comes in.
Why would c.print()
print out I am a square of side 6.0
?
Upvotes: 1
Views: 25742
Reputation: 16117
In (Java) inheritance that is the intended behavior -- polymorphy -- it's a way for you (the developer) to design an application around a concept (rectangles) and allow other related concepts (squares) to be used in places where the original concept (rectangle) is used but with their own (square) behavior.
Imagine you'd have a list or array of rectangles and you'd fill it with objects received from returns of functions from outside your own package. Then you'd iterate over the list and ask each object to do things -- it is normal to want those objects to behave as what they really are, not as what they're filling in for.
If you ask a rectangle what its area is it will multiply length and width and return the result. If you don't override that in the square class it will do the same thing but you could override it and it could calculate its area as Math.pow(this.side, 2)
.
How about this inheritance chain:
Shape > Polygon > Quadrilateral > Parallelogram > Rectangle > Square
You would definately need to implement different area calculation methods -- wouldn't you want each object to behave as its own underlying structure tells it to (instead of behaving like the type it's been cast to)?
Upvotes: 1
Reputation: 1315
I think this is the modification you need:
public static class Rectangle
{
protected double length;
protected double width;
public Rectangle(double length, double width)
{
this.length = length;
this.width = width;
}
public Rectangle(Rectangle r)
{
this.length = r.length;
this.width = r.width;
}
public void print()
{
System.out.println("I am a rectangle of length " + length + " and width " + width);
}
}
public static class Square extends Rectangle
{
public Square(double side)
{
super(side, side);
}
public void print()
{
System.out.println("I am a square of side " + length);
}
}
public static void main(String[] args)
{
Square b = new Square(6.0);
Rectangle c = new Rectangle(b);
c.print();
}
Your Square
class has nothing to do with Rectangle
class. It has a different attribute. If you are using inheritence, base class should inherit something.
Moreover, there is no print()
method in Rectangle
.
A simple copy constructor, making your base class members protected
and deleting the unnecessary derived class members should work.
Upvotes: 0
Reputation: 280054
This assumes Rectangle
declares a print()
method.
This action
Rectangle c = (Rectangle) b;
doesn't do anything to the instance referenced by b
. It only widens the reference variable b
to its super type Rectangle
.
Invoking print()
will have polymorphic behavior and, at runtime, the implementation of Square
will be used since c
is referencing a Square
object, which has set size
to 6
.
Square b = new Square(6.0);
...
private double side;
public Square(double side) {
super(side, side);
this.side = side;
}
Note that this is the expected behavior in Java since all methods are virtual by default. In other languages like C++ and C#, your cast would have worked since print
method in Rectangle
isn't declared as virtual
.
More info:
Upvotes: 3
Reputation: 93
Remember that c
is just a reference to an object in memory. The object being referenced is of dynamic type Square, despite the reference c
being of static type Rectangle. The distinction between static and dynamic typing is crucial to this example.
The static type associated with a reference to an object is what the compiler uses to ensure that our code makes sense from a type perspective. When one calls a method on an object, however, which method is called depends on the dynamic type of the object, i.e. the type of object actually being referenced at runtime. This is called dynamic binding.
It also bears mentioning that the Rectangle-Square example is a canonical one. It is usually used to illustrate how thinking of types and supertypes as categories and generalizations can be misleading. Following the Liskov substitution principle requires writing the classes the other way, with Rectangle extends Square
. This is another important idea of Object-Oriented Programming being touched on.
Upvotes: 0
Reputation: 2923
Because of inheritance, every Square
is also a Rectangle
. When you cast it to shove a Square
in a Rectangle
variable, it retains its Square
ness. In this example, either a Square
or a Rectangle
can be put in your c
. Polymorphism means that the method on whatever class it really is will be used.
Upvotes: 0
Reputation: 57202
This is polymorphic behavior. The actual type of the class determines the method that is called. Square
's version of print
will be called since the actual type of the object is Square
.
Upvotes: 1