Dec 2, 2011

Polymorphism via Inheritance and Interface

Polymorphism: So it means entity that can have many forms. More specifically, a reference variable that can refer to different types of objects at different points of time. The specific method called through a polymorphic reference can change from one invocation to any subsequent invocations.
Java allows two kinds of polymorphism reference:

Polymorphism through inheritance:
For example think of a class hierarchy Object -> Animal -> Mammal -> Tiger
Animal objAnimal;
Mammal objMammal;
Tiger tigerObj = new Tiger("Bengal Tiger");
objAnimal = tigerObj; // Valid. objAnimal.move() will invoke the move method of Tiger class
objMammal = tigerObj // Valid. objMammal.move() will invoke the move method of Tiger class
objAnimal = new Tiger("Siberian Tiger"); // Valid. objAnimal.move() invoke the move() of Tiger class
Object obj = new Tiger("Thai Tiger"); // Valid. obj.move() will invoke the move method of Tiger class

At any point of time objAnimal can be used polymorphically, because it can refer to Animal object, Mammal object, or Tiger object. Particular version of move method that will be used depends on what kind of reference the objAnimal holds at a particular moment. Usually the children classes over-rides the method definitions. So each of the children in the Animal hierarchy has an different definition of move(). Depending on the reference class it is currently pointing to, a particular implementation of the move will be invoked.

Even if Mammal's move method is abstract it can invoke any of its children's move() (for example Tiger, Lion, Dolphin can have different implementation of move methods. Mammal reference can be used to instantiate any of these three objects and can be used to invoke move method at different points of time.)

Tiger tigerObj2 = objAnimal. //INVALID

Tiger tigerObj2 = (Tiger)objAnimal. //Valid.
But tigerObj may not have all the properties now because it is down-casted from its ancestor. It is less useful and tend to create problems.


Polymorphism through interface:
Interface can also have hierarchy. Child interface inherits all the methods/constants of its parents. No visibility issue since all methods and constant members are public.
An interface can be used to refer to any object of any class that implements it.

public interface Singer{
 public void sing();
 public void scream();
}

Singer singer = new ClassicalMusician(); // Valid
ClassicalMusician class implements the Singer interface. So singer reference can be used to refer to an object of ClassicalMusician.
singer.sing() //Valid
singer = new Cuckoo(); //Valid assuming Cuckoo class implements Singer interface.
singer.scream(); //Valid

Polymorphism via interface is different from polymorphism via inheritance in a sense that here the type of the object that the reference points to at the moment of invocation determines what code will be executed.

Unlike polymorphism via inheritance, we are allowed to invoke only those methods that are defined in the interface (in example more specifically the sing() and scream() methods only). If singer currently refers to an object of Cuckoo class, and singer invokes a singer.buildNest(), method from the Cuckoo, it will produce a compiler error.

However, if we have the knowledge in a particular situation that such invocation is valid, we can cast the object into the appropriate reference so that the compiler will accept it:
(Cuckoo)singer).buildNest(); //Valid. singer is converted to an object of Cuckoo then the buildNest() is invoked.

An interface name can be used as the type of a method parameter. In such situation, any object of any class that implements the interface can be passed into the method.
public void operaSinging(Singer obj) {
   obj.sing();
}

Then we can pass instance of ClassicalSinger or an instance of Cuckoo to the operaSinging() method as a parameter.


No comments:

Orpheus and Eurydice