Polymorphism and its implementation in Java (Part I)

by Barry Nirmal

Go to Part II of this article.

Abstract: In this article, we discuss the concept of polymorphism and how it is implemented in Java based systems. The Java classes given in this article are complete and can be compiled without change. Unlike some other articles which use unrealistic examples to illustrate concepts, we use realistic and practical examples drawn from the real world. This will enable the reader to gain a firm grasp of the concepts.

Polymorphism is an important concept in object-oriented system design. Every designer of object oriented systems must have a firm grasp of this concept. In Java the concept of polymorphism is closely related to concepts of abstract classes and interface. It is with the aim of clarifying these concepts that this article was written.

Polymorphism generally means the ability to appear in many forms. However, in object-oriented programming, polymorphism refers to a programming language's ability to process objects differently depending on their data type or class. More specifically, it is the ability to redefine methods for derived classes. For example, given a base class shape, polymorphism enables the programmer to define different circumference methods for any number of derived classes, such as circles, rectangles and triangles. No matter what shape an object is, applying the circumference method to it will return the correct results. Polymorphism is considered to be a requirement of any true object-oriented programming language (OOPL).

The shape class can be implemented in Java as follows.


abstract class Shape {

  abstract double calcCircumference ();

}





class Rectangle extends Shape {

double x,y ;



public Rectangle (double x, double y) {

   this.x = x;

   this. y = y;

}



  double calcCircumference  ( ) {

    double circum = 2.0 * x + 2.0 * y ;

    return (circum);

  }

}



class Circle extends Shape {



double radius;



  public Circle (double radius ) {

   this.radius  = radius ;

}



  double calcCircumference ( ) {

    double circum = 2.0 * 3.1415 * radius;

    return (circum);

  }

}

Given this inheritance hierarchy, polymorphism allows you to hold a reference to a Circle object in a variable of type Shape, as in the following class:




class Test   {



public static void main  (String args[]  ) {



Shape shape1 = new Rectangle (5.0, 10.0);

Shape shape2 =  new Circle (20.0);



GiveCircum.  printCircum (shape1);

GiveCircum . printCircum  (shape2);



}



}





class GiveCircum    {



public static void  printCircum (Shape s) {

  double result =  s. calcCircumference ()  ;

  System.out.println ("hello - circumference = " + result ) ;



}



}

So, polymorphism allowed us to hold a reference to a Circle object in a variable of type Shape as in:




Shape shape1 = new Rectangle (5.0, 10.0);

Also note that at compile time, the compiler doesn’t know exactly which class of object will be passed to printCircum() at runtime. It only knows that the object will be some subclass of Shape. Furthermore, the compiler doesn’t know exactly which implementation of calcCircumference() should be invoke at runtime.

So dynamic binding means that the JVM will decide at runtime which method to invoke based in the class of the objet. If the object is a Circle, the JVM will invoke Circle’s implementation of the method. If the object is a Rectangle, the JVM will invoke Rectangle’s implementation of the method.

So, dynamic binding is the mechanism that makes polymorphism, or “substitutability of a subclass for a superclass” possible.

Why is polymorphism such a good thing?

Polymorphism helps make programs more flexible because at some future time, you can add another subclass to the Shape family, and the printCircum() method will still work. For example you can later add a Hexagon class, a Square class, or a Pentagon class.

Can an abstract class implement a method?

Yes they can. In the example above, we can change Shape class as follows:


abstract class Shape {

  int x, y;

  void moveTo ( int newx, int newy) {



  }



  abstract double calcCircumference ();



}



(Continued onto Part II) .....
Click here to go to Part II.