Java With Us
Home   |   Tutorial   |   Programs  

Java Tutorial

Introduction to Java
Hello World Program
Variables and Data types
More about data types
Displaying text using print and println
Displaying text using printf
Java Comments
Naming conventions for Identifiers
Mathematical operations in Java
Taking input from the user

Classes and Objects
Introduction to object oriented programming
The constituents of a Class
Creating objects and calling methods
Get and Set Methods
Default constructor provided by the compiler
Access Specfiers
Scope and lifetime of Variables
Call by value and Call by Reference

A few more topics
Casting
Class as a reference data type
Constants or literals
Final variables
Increment and decrement operators
Manipulating Strings
Operators
Overloading constructors and methods
Static methods and variables
The Java API
The Math class
this keyword
Wrapper classes

Control Structures
Control Statements
Repetition statements
Nested loops
Formulating algorithms
Branching Statements

Arrays
Arrays introduction
Processing arrays using 1oops
Searching and sorting arrays
Array of objects
Multi dimensional arrays
Taking input as command line arguments
Using ellipsis to accept variable number of arguments

Inheritance
Inheritance introduction
Relation between a super class and sub class
Final classes and methods
The protected access specifier
Class Object

Polymorphism
Introduction
Interfaces
Packages
Abstract classes and methods

Exception handling
Exception handling introduction
Exception hierarchy
Nested try catch blocks
Throwing exceptions


Polymorphism

Polymorphism is an object oriented programming feature which allows the same message to produce different but correct outputs. One example is the case of method overloading, the same message sent ( invoking the method) produces the desired and correct output by resolving the call to the appropriate method based on the parameters passed. And now, we shall see polymorphism in the context of inheritance. Polymorphism allows us to program in the general rather than in the specific. We have already come across polymorphism in the context of inheritance when we have overridden the printDetails() method in the Student class. Invoking it has called the sub class version and not the super class version. We shall continue a similar discussion, using a different and more appropriate example to illustrate programming in the general.

We have a class named Animal having a method move(). An animal may move in different ways, it might swim like a fish, fly like a bird or crawl like a spider. So the class Animal is more general, so is the method move(). We then extend this superclass Animal to a few subclasses like Fish, Spider and Bird which override the method move() to define a more specific implementation of the method move(). For now, here are the various class definitions.

public class Animal {
    public void move() {
     System.out.println("The animal is moving");
    }
}

public class Bird extends Animal{
    public void move() {
     System.out.println("The bird is flying");
    }
}

public class Fish extends Animal{
    public void move() {
     System.out.println("The fish is swimming");
    }
}

public class Spider extends Animal{
    public void move() {
     System.out.println("The spider is crawling");
    }
}

public class Hare extends Animal{
    public void move() {
     System.out.println("The hare is running");
    }
}

Animal is a more general class and the sub classes are more specific in nature. There is also a possibility that we may feel like adding more Animal types or subclasses of Animal in the future. So, rather than programming with respect to a specific animal, we simply program in the general taking only the Animal class into consideration and not its specific sub classes.

To understand what programming in the specific and general means, let us assume that we need to create ten different objects, some of them of Bird type, a few others of Spider type and so on. And then make each of these animals move. One solution would be the following where we consider each animal to be of a separate type. This might be named as programming in the specific.

Fish f1 = new Fish();
Fish f2 = new Fish();
Bird b1=new Bird();
...
f1.moev();
f2.move();
f3.move();
...

This approach seems alright but what if we have 100 such different animals, a few in each category? And if is not just one method that we need to invoke but several of them, all of them having the same name and defined in each of the classes. One solution would be to use arrays. Now, here arises the question. Do we create Fish arrays, Bird arrays or Animal arrays. If we go for creating a different typed array for each of the Animal types, modifying the code would be difficult if new Animal types like Crabs and Monkeys come into the picture. So, we better choose to create arrays of Animal type. But, would move() invoked on Animal type objects call the version in the superclass or the sub class? As we have already seen when earlier, during compilation, the method call is resolved by looking at the variable type which in this case is Animal. So each of the move() calls would be mapped to the versions in superclass. However, the actual method being called is decided during time by looking at the type of object and not the type of variable. If the sub class has overridden any of the already matched methods during compilation, the call would be diverted to the sub class method. So, the correct version is guaranteed to be called. This is what we refer to as programming in the general and this resolution of calls during run time is known as dynamic binding or run time polymorphism. Actual use of this feature is quite more complicated and is used as a part of actual reusable class. But, for illustrative purpose, we use it in test class as shown below:

public class Test{

    public static void main(String [] args){
    Animal[] animals=new Animal[4];
    animals[0]=new Fish();
    animals[1]=new Spider();
    animals[2]=new Bird();
    animals[3]=new Hare();
    for(int i=0;i<animals.length;i++)
     animals[i].move();
    }


The output would be:

The fish is swimming
The spider is crawling
The bird is flying
The hare is running

To make this program more interesting, provide parameterised constructors for the sub classes of Animal so that we may give names to the animal and modify the move() method to display the name of the animal along with the action being performed.

Method call resolution during run time occurs to the deepest level. For example, if in the above program, we further extends Bird to Sparrow overriding method move(), create a Sparrow object, assign its reference to an Animal variable and then invoke the move() method, the call gets resolved to the version in Sparrow and not to the one in Bird() or Animal().

Next : Interfaces
Prev : Class Object
Privacy Policy