9.7 Polymorphism

One of the key features of inheritance is that a reference variable of a superclass type can point to an object of its subclass. Polymorphism is the art of taking advantage of this simple but powerful and versatile feature.

Consider the following example, Shape is super class for Rectangle and Triangle class.

polymorphism-inheritance

Look at the following statement that declares a reference variable named rect:

Rectangle rect;

This statement tells us that the rect variables data type is Rectangle. Therefore, we can use the rect variable to reference a Rectangle object, as shown in the following statement:

rect = new Rectangle();

In above figure the Shape class is used as the superclass for the Rectangle class. Therefore an object of the Rectangle class is not just a Rectangle object. It is also a Shape object. In other words, we can use a Shape type reference variable to reference a Rectangle object :

Shape shape; 
shape = rect; // shape point to the object rect. 

After the above statement executes, the object is treated as an object of the class Shape. Therefore following statement is legal.

shape.setValues(4,5); // Set values in rectangle object.

Now consider the statement, we wants to call getArea method using shape reference variable.

double a = shape.getArea(); //illegal

Although a shape variable can reference object of class that extends Shape but a shape variable can be used to call only those methods defined inside Shape. So in order to access getArea method of Rectangle class, we will use Rectangle type reference variable. As shown in following statement :

double a = rect.getArea(); // legal

Similarly Triangle is also sub class of Shape class. So all statements are same for triangle object.

So we can summarize this with the statement that Super class reference
variables are polymorphic reference variables. They can refer to objects of their own class or to objects of the subclasses inherited from their class.

Here is complete program :

Program (Shape.java)

/**
 *  A class Shape that holds width and height
 *  of any shape
 */

public class Shape
{
   private double height;  // To hold height.
   private double width;  //To hold width or base

   // Set height and width
   public void setValues(double height, double width)
   {
      this.height = height;
      this.width = width;
   }

   //Get height
   public double getHeight() 
   {
       return height;
   }
     
   //Get width
   public double getWidth() 
   {
       return width;
   }    
}            

Program (Rectangle.java)

/**
 *  This class Rectangle calculates 
 *  the area of rectangle 
 */

public class Rectangle extends Shape
{
    //Calculate and return area of rectangle
    public double getArea()
    {
        return getHeight() * getWidth();
    }
}

Program (Triangle.java)

/**
 *  This class Triangle calculates 
 *  the area of triangle 
 */

public class Triangle extends Shape
{ 
    //Calculate and return area of triangle
    public double getArea() 
    {
        return (getHeight() * getWidth()) / 2;
    }
}       

Program(PolymorphismDemo.java)

/**
 * This program demonstrates polymorphic behavior.
 */

public class PolymorphismDemo
{
    public static void main(String[] args)
    {
        Shape shape;
        
        // assign subclass reference to subclass variable
        Rectangle rect = new Rectangle();
        
        // shape points to the object rect.
        shape = rect;

        // Set data in Rectangle's object 
        shape.setValues(78, 5);
        
        //Display the area of rectangle
        System.out.println("Area of rectangle : " + rect.getArea());
        
        // assign subclass reference to subclass variable
        Triangle tri = new Triangle();
        
        // shape points to the object rect.        
        shape = tri;
        
        // Set data in Triangle's object         
        shape.setValues(34,3);
        
        //Display the area of triangle        
        System.out.println("Area of triangle : " + tri.getArea());
    }
}

Output :
Area of rectangle : 390.0
Area of triangle: 51.0

 

Upcasting and Downcasting

As illustrated above, a reference variable of a superclass type can point to an object of its subclass. This is known as upcasting :

Shape shape; 
Rectangle rect = new Rectangle();
shape = rect; // Upcasting 

Or we could do something equivalent, such as

Shape shape = new Rectangle();   // Upcasting 

Upcasting occurs automatically. Downcasting occurs when a type cast is performed from a super class to a sub class. Downcasting must be done very carefully.

Shape shape;
Rectangle rect;
rect = (Rectangle)shape; // Downcasting 

 

The instanceof Operator

The instanceof operator is an boolean operator that tests whether an object belongs to a given class.

Consider the following expression

rect instanceof Rectangle

This is the form of a boolean expression that will return true if the object referenced by rect is an instance of Rectangle. Otherwise, the expression returns false.

Following code segment illustrates how the operator instanceof works :

Rectangle rect = new Rectangle();

if (rect instanceof Rectangle)
   System.out.println("Yes, rect is an instance of Rectangle.");
else
   System.out.println("No, rect is not an instance of Rectangle.");

This code will display "Yes, rect is an an instance of Rectangle."

The instanceof operator recognizes an object as being of a given type, even if that type is a superclass of the actual type of the object. For example, look at the following code:

Rectangle rect = new Rectangle();

if (rect instanceof Shape)
   System.out.println("Yes, rect is an instance of Shape.");
else
   System.out.println("No, rect is not an instance of Shape.");


Even though the object referenced by rect is a Rectangle object, this code will display "Yes, rect is an instance of Shape."

The instanceof operator returns true because Rectangle is a subclass of Shape.