PolymorphismHomepage  « Learn Java5 « Polymorphism

In this lesson we continue our investigation of OO concepts by learning about polymorphism, which roughly translated from the Greek means 'the ability to assume different forms'. So what does this mean for us Java programmers? To explain this we will refresh our memory about how we create an object:

object creation

So lets go through the three step process above:

  1. Declaration - Here. we declare a reference type named garbage of type Garbage and the JVM allocates space for it.
  2. Creation - Tells the JVM to allocate space on The Heap for a new Garbage object.
  3. Assignment - Assign the new Garbage object to the reference type garbage.

The reference type and the object type are the same.

Polymorphic Method Invocationgo to top of page Top

With polymorphism when you declare the reference type in the declaration, it can be from a superclass of the object we are creating. Or looking from a different perspective, when creating an object, we can use any supertype from a class that we have extended. The compiler has no problem with this but the power of polymorphism happens at runtime through the concept of virtual method invocation. This concept is the dynamic selection of overridden methods at runtime based on the actual object type, rather than the reference type. This only applies to instance methods, everything else uses the reference type at runtime.

object creation

So what does this give us I hear you ask? Well we can use the supertype for reference type declaration when instantiating our objects, safe in the knowledge that the JVM will use the actual object created to invoke the correct overridden methods of the subtypes at runtime. This ties in with the concept of abstraction that we looked at in the last lesson. By making generic methods abstract in the superclass we can be assured that the overridden method implementations are in place in the subclass at runtime. If you remember we have to implement all abstract methods from the superclass in the first concrete subclass. We will use an array to illustrate polymorphic method invocation:


/*
 Polymorphic Array 
*/ 
public class PolymorphicArray {

    public static void main (String[] args) {
        Truck[] truck = new Truck[2];  // Array declaration
        truck[0] = new HGV(); 
        truck[1] = new Garbage();
        for (int i=0; i < truck.length; i++) {
            truck[i].load("stuff");
        } 
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run Polymorphic Array

The above screenshot shows the output of running our PolymorphicArray class. The JVM uses virtual method invocation to dynamically invoke the correct subtype override. The overrides in the HGV and Garbage classes are shown below:


public class HGV extends Truck {
    public void load(String payload) {
        System.out.println("We are transporting " + payload + " in our Heavy Goods Vehicle." );
    }
}
public class Garbage extends Truck {
    public void load(String payload) {
        System.out.println("Our garbage truck eats " + payload);
    }
}

We can happily include new subtypes in the knowledge that any method overrides will be called correctly on that subtype.

Polymorphic Argumentsgo to top of page Top

We can also make the arguments to our methods polymorphic. We will write a new class and a test to see this in action:


/*
  A Transit Class
*/ 
public class Transit {
    private int capacity = 4;

    public void hold(Vehicle v) {
        v.carry(capacity); 
    }
}

Save and compile the file in directory   c:\_OOConcepts in the usual way.

Here's our test class .


/*
 Test class for polymorphic arguments
*/ 
public class TestPolyArgs {

    public static void main (String[] args) {
        Vehicle bus = new Bus();  
        Vehicle hgv = new HGV();  
        Transit transit = new Transit(); 
        transit.hold(bus);
        transit.hold(hgv);
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run Polymorphic Array

The above screenshot shows the output of running our TestPolyArgs test class. As you can see we are passing the Vehicle supertype as an argumment to the hold() method. The JVM uses virtual method invocation to dynamically invoke the correct Carry() method based on the actual object type at runtime.

Polymorphic Return Typesgo to top of page Top

Lastly we will look at using polymorphic return types. We will write a new test class to see this in action:


/*
 Test class for polymorphic return
*/ 
public class PolymorphicReturn {

    public static void main (String[] args) {
        // Array declaration below is creating an Array object so can use Abstract supertype
        Vehicle[] vehicle = new Vehicle[4];  
        for (int i=0; i < 4; i++) {
            vehicle[i] = createVehicle(i);
            vehicle[i].carry(i);  
        } 
    }
    /*
      Create a Vehicle subtype and return the Vehicle supertype
    */ 
    static Vehicle createVehicle (int i) {
        Vehicle vehicle;
	    switch (i) {
            case 0:
                vehicle = new Car();
                break;
            case 1:
                vehicle = new HGV();
                break;
            case 2:
                vehicle = new Bus();
                break;
            default:
                vehicle = new Garbage();
	    }
        return vehicle;
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run Polymorphic Array

The above screenshot shows the output of running our slightly contrived PolymorphicReturn test class. We are returning the Vehicle supertype from the createVehicle() method. The JVM uses virtual method invocation to dynamically invoke the correct Carry() method based on the actual object type on return.

We will return to polymorphism when we look at polymorphic interface arguments and polymorphic interface return types in the Deeper Into Polymorphism section of the next lesson.

Static Overrides?go to top of page Top

I know what you're thinking, what on earth is something about statics doing in a section on polymorphism. Well, now we have talked about how polymorphism works I just want to hammer home the point that it only relates to overridden instance methods and nothing else. I also wanted to talk about method hiding which relates to static methods in a subclass with the same identifier in the superclass. To look at this we first had to get our heads around the idea of virtual method invocation and how this works with supertypes and subtypes. Now that is done we can use the same principle to look at method hiding:


/*
 Superclass to illustrate method hiding
*/ 
public class A {

    public static void aClassMethod() {
        System.out.println("The class method in A.");
    }
    public void anInstanceMethod() {
        System.out.println("The instance method in A.");
    }
}
/*
 Subclass to illustrate method hiding
*/ 
public class B extends A {

    public static void aClassMethod() {
        System.out.println("The class method in B.");
    }
    public void anInstanceMethod() {
        System.out.println("The instance method in B.");
    }
}
/*
 Test Class to illustrate method hiding
*/ 
public class TestHiding {

    public static void main(String[] args) {
        B b = new B();
        A a = b;
        A.aClassMethod();
        a.anInstanceMethod();
    }
}

In the above code the aClassMethod() static method in class B hides the aClassMethod() static method in class A. The anInstanceMethod() instance method in class B overrides the anInstanceMethod() instance method in class A.

run Polymorphic Array

The above screenshot shows the output of running our TestHiding test class after compiling classes A and B. As you can see the aClassMethod() static method from the superclass gets invoked via the class name. The overridden anInstanceMethod() instance method from the subclass gets invoked via the object type.

Polymorphism Quizgo to top of page Top

Try the quiz below to test your knowledge of this lesson

Question 1 : What is required to use polymorphism?
- We need to have an inheritance hierarchy to use polymorphism, although abstracting out generic methods to force implementation in subclasses helps to enforce it.
Question 2 : What do we use in the declaration of an object to enable polymorphism?
- We use the supertype of the object we are creating
Question 3 : What are used for polymorphism?
- <em>overridden</em> instance methods are used in polymorphism.
Question 4 : We use overloaded methods in polymorphism?
- We use <em>overridden</em> methods in polymorphism.
Question 5 : What is the following code snippet an example of?

public class A {
public static void aClassMethod() {
}
}
public class B extends A {
public static void aClassMethod() {
}
}
- This is an example of <em>hiding</em>.
Question 6 : Assuming the following are in different files is the following code snippet valid?

public class A { public void a() {} }
public class B extends A { public void a() {} }
public class TestAB {
public static void main(String[] args) {
B b = new A();
b.a();
}
}
- Class <code>TestAB</code> doesn't compile because of incompatible types. We can't use the <em>subclass</em> as the refernce type to a <em>superclass</em>.
Question 7 : What is the dynamic selection of overridden methods at runtime based on the actual object type, rather than the reference type known as?
- This concept is known as <em>virtual method invocation</em>.
Status Bar Please select an answer

What's Next?

In the next lesson we examine interfaces and the contracts we provide when using them.

<<  Abstraction                    Interfaces  >>

go to home page Java5 Tutor Homepage go to top of page Top