Skip to main content

Polymorphism in Java

Posted by hellofadude on January 7, 2014 at 1:16 PM PST

In object oriented programming, polymorphism is a feature that allows you to provide a single interface to varying entities of the same type. This is analogous to the interpretation of the same concept in the field of Biology.

To understand how this works in Java, we must consider inheritance and the ways by which the Java programming language makes method calls.

When you create a class in Java, you implicitly inherit the fields and methods of the root Object class even when you do not explicitly inherit from some other class. This ability allows you to substitute an object for its base class and is proof of the saying - "in Java everything is an object".
To demonstrate, we consider the simple example of Shape objects:-

    class Shape { 
         public String toString() {
              return " a Shape";
         }
    }
    class Triangle extends Shape {
         public String toString() {
              return "a Triangle";
         }
    }
    public class DrawShape {
        /**
        * @param args
        */
        static void draw(Shape s) {
            System.out.println("Drawing " + s);
        }
        public static void main(String[] args) {
            Triangle t = new Triangle();
            draw(t);
            // TODO Auto-generated method stub
       }
   }

   /* Output
   Drawing a Triangle
   *//

What is interesting about this example is how in the main(), we pass a Triangle reference to the draw() method that expects a Shape reference. What is even more interesting is how the compiler accepts this without complaint and Java is able to make the correct method call at run time and without the need for upcasting. This is essentially how polymorphism works. Because the draw() is a dynamically bound method (as are all normal methods in Java), a programmer is able to ignore types and write methods that takes a base class as argument confident in the knowledge that such methods can also be applied to derived classes.
Here is a slightly modified version of the example to better elucidate my point:-
    class Shape { 
         public void draw() {
              System.out.println("Drawing a Shape");
         }
    }
    class Triangle extends Shape {
         public void draw() {
              System.out.println("Drawing a Triangle");
         }
    }
    public class DrawShape2 {
        /**
        * @param args
        */
        public static void main(String[] args) {
           Shape s = new Triangle();
            s.draw();
            // TODO Auto-generated method stub
       }
   }

   /* Output
   Drawing a Triangle
   *//

In this example, we assign a Triangle object to a Shape reference. A call to the overloaded draw() method produces the correct behaviour, when it might be reasonable to expect that the draw() method in the Shape object might be bound to the call; afterall, we are speaking of a Shape reference. However on closer inspection, the output makes sense because a Triangle object is a kind of Shape, a fact concretised by the use of the extends keyword that denotes the use of inheritance.
You might wonder how it is that this is possible? I mean how does Java know what method to call in order to produce the correct behavior at run time? This is essentially what polymorphism is designed to achieve.

To get a better understanding of how it works we might consider the concept of binding which refers to the process of connecting a method call to a method body.
In programming, early binding references the point when the binding process is performed before the program is run. This is typically done by the compiler and is synonymous with some procedural languages. In the above example, it is clear that the compiler can not know which method to call when it only has a Shape reference from which we have derived at least one other type.

To overcome this, Java uses the concept of late binding or dynamic binding, which allows binding to occur at run time. The term dynamic binding is often used to refer to polymorphism. When we say all method calls in Java happen polymorphically, we may correctly imagine the implementation of some mechanism that allows the correct object type to be determined at run time. The mechanism of this invention however, is not of itself of any interest to us, but the ways by which it might be perceived.

Polymorphism and constructors.

Constructors in Java are not known to be polymorphic and there is disagreement as to whether they constitute static methods or not. Be that as it may, it has been suggested in other well regarded text that constructors are indeed implicitly static and we are happy to retain this view in the absence of anything to suggest the contrary. In the previous example, we demonstrated how polymorphism allows us to substitute a simple Triangle object for its base class. In this section we aim to explain how polymorphism effects a more complex type and the order of construction of such objects. The example below gives an idea of what a complex class looks like:-

    class Books {
        Books() {
           System.out.println("Books");
    }
    class Computers {
        Computers() {
            System.out.println("Computers");
        }
    }
    class Address {
        Address() {
            System.out.println("Address");
        }
    }
    class Building extends Address {
        Building() {
            System.out.println("Building");
        }
    }
    public class Library extends Building {
         /**
         * @param args
         */
         private Books bs = new Books();
         private Computers cp = new Computers();
         public Library() {
             System.out.println("Library");
         }
         public static void main(String[] args) {
             // TODO Auto-generated method stub
             new Library();
        }
     }
    /* Output
    Address
    Building
    Books
    Computers
    Library
     *//

The example demonstrates the effect of polymorphism on the order of constructor calls in Java. The Library class is an example of a more complex type reflecting at least two levels of inheritance as well as being composed of a number of other objects. Notice how a call to the Library() constructor results in a call to its base classes in a sort of recursive manner as can be evidence by the output. The logic of this is inherent in the fact that for a derived class to be properly constructed, the base classes from which it is derived must first be properly initialised. In other words, an inherited class must know all about its base class or classes and be able to access all of its public and protected elements.
What we are trying to say is when you have a complex class that makes use of composition and inheritance, the order of constructor calls begins by first calling the base class constructor at the root of the hierarchy, followed by other constructors within the hierarchy in a sort of recursive and sequential manner.

It is only after this process has been completed that individual members within the class are initialised in the order in which they are written, after which the derived class constructor may then be called. There is sufficient evidence of this in the above output.

As mentioned previously, Java applies late binding to all normal method calls. This means that all methods with the exception of constructors are polymorphic by default. It is important to remember that this has an impact when you try to call a dynamically bound method from within a class constructor. In these circumstances, the overridden method may be called before the object is fully constructed making it more likely that you might end up using an unintialised variable, which might result in hard to find bugs in your program.

The best way to avoid such a scenario is to do as little as possible within your constructors to get the object into a proper state. However if you must call a dynamically bound method within your constructor, the only safe methods to call are those declared final and private which cannot be overridden.

When you declare a method final you effectively place a lock on it and prevent inheriting classes from changing its meaning. This is of course a design consideration. By the same token, methods declared private are implicitly final and therefore can not be accessed or overridden by inheriting classes.

Summary

In this post we have identified the effect of polymorphism on objects of derived classes, how such classes can be substituted for their base classes and as a consequence the order of constructor calls on objects of classes composed by means of composition and inheritance. Polymorphism is an essential construct in any OOP language as it works with essential features like inheritance and encapsulation and provides you with the ability to use the same interface with different forms. Having a proper understanding of how polymorphism works helps improve your code design with several desirable characteristics such as extensibility, readability and better code organisation.

contact me @ kaseosime@btinternet.com

Comments

I just want to clarify that a constructor is not ...

I just want to clarify that a constructor is not static.

A static method:
- is marked with the "static" keyword.
- is compiled with the "ACC_STATIC" flag
- is invoked with the "invokestatic" opcode

A constructor:
- is NOT marked with the "static" keyword
- is NOT compiled with the "ACC_STATIC" flag
- is NOT invoked with the "invokestatic" opcode, but with the "invokespecial"