1

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?

theGreenCabbage
  • 5,197
  • 19
  • 79
  • 169
  • 1
    What do you expect it to print? – Sotirios Delimanolis Apr 29 '14 at 00:30
  • 1
    That won't even compile – Abimaran Kugathasan Apr 29 '14 at 00:35
  • What's the point of using inheritance if all your class members are `private`? – padawan Apr 29 '14 at 00:39
  • 2
    @cagirici not sure if this is the right time in OPs learning stage to learn about good practices and design patterns -- since he's only now understanding the language (and perhaps even general OOP). – Mihai Stancu Apr 29 '14 at 00:42
  • For readers (including people who will try to answer this question): Assumming `print` is a non-virtual method declared in `Rectangle` class, then this code would have behaved as defined in `Rectangle` class. `virtual` allows polymorphism, and in Java all methods are virtual by default. – Luiggi Mendoza Apr 29 '14 at 00:45
  • Unfortunately guys, this is an example taken from my basic Java practices. No arguments can be done on whether practice A or B is better, or why this code is sampled; it's all dictatorially asserted that "here is an example, tell me what it does". Welcome to the American CS education. – theGreenCabbage Apr 29 '14 at 01:40
  • @theGreenCabbage Educational systems in most places have their own handicap. In some fields they have an advantage big enough to ignore the handicap (hardware technology, medicine, etc. they all require expensive learning "tools"). In some theoretical fields they have the advantage of having already digested the theory for you. But in CS the can offer you little hardware support which you don't already have access to, and little pre-digested theoretical support. – Mihai Stancu Apr 29 '14 at 15:51
  • @theGreenCabbage none of us would be here in the CS field without passion, curiosity, individual research and lots of trial and error. – Mihai Stancu Apr 29 '14 at 15:55

6 Answers6

3

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:

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Does this mean that even though `c` is the object-type `Rectangle`, it still references `b` because, as you said, `c` is referencing a `Square` object? – theGreenCabbage Apr 29 '14 at 00:37
  • @theGreenCabbage You have to make the distinction between a variable and an instance. A variable references an instance. The variable has a declared type (or static type) and references an instance which has a dynamic type (runtime type). Since a `Square` is a `Rectangle`, you can reference it with a variable with a declared type of `Rectangle`, but the object is still a `Square`. – Sotirios Delimanolis Apr 29 '14 at 00:39
  • @theGreenCabbage this is the correct answer, but I've provided another answer to complement this info. – Luiggi Mendoza Apr 29 '14 at 00:40
  • Could we assume that no matter how many extension classes we have, using cast would not change the behavior of that super class? – theGreenCabbage Apr 29 '14 at 00:41
  • 1
    @theGreenCabbage yes, you can assume that **for Java**. – Luiggi Mendoza Apr 29 '14 at 00:43
  • `Square b = new Square(6.0);` `Dodecahedron c = (Dodecahedron) b;` Printing the above two lines would still return `Square is side 6.0` is that right? – theGreenCabbage Apr 29 '14 at 00:45
  • @theGreenCabbage That's right. The lowest implementation in the inheritance hierarchy will be invoked. (I assume here `Dodecahedron` is really high in the hierarchy.) – Sotirios Delimanolis Apr 29 '14 at 00:46
  • @theGreenCabbage Ok wait. If `Dodecahedron` is a sub class of `Square`, what you just did with throw a `ClassCastException` because a `Square` is not a `Dodecahedron`. – Sotirios Delimanolis Apr 29 '14 at 00:47
  • @theGreenCabbage by the way, next time try to choose a better example. `Rectangle` and `Square` inheritance are a bad example because they don't pass the [Liskov substitution principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle#A_typical_violation). – Luiggi Mendoza Apr 29 '14 at 00:50
1

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.

Jeff Storey
  • 56,312
  • 72
  • 233
  • 406
1

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)?

Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51
0

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.

matthugs
  • 85
  • 1
  • 7
0

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.

Ben N
  • 2,883
  • 4
  • 26
  • 49
0

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.

padawan
  • 1,295
  • 1
  • 17
  • 45