theGreenCabbage
theGreenCabbage

Reputation: 4845

Square and Rectangle Inheritance

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

Answers (6)

Mihai Stancu
Mihai Stancu

Reputation: 16117

Polymorphy

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.

Practicality

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

padawan
padawan

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

Sotirios Delimanolis
Sotirios Delimanolis

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

matthugs
matthugs

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

Ben N
Ben N

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 Squareness. 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

Jeff Storey
Jeff Storey

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

Related Questions