Polymorphism means "many forms", and it occurs when we have many classes that are related to each other by inheritance.
Inheritance lets us inherit attributes and methods from another class. Polymorphism uses those methods to perform different tasks. This allows us to perform a single action in different ways.
Polymorphism in Java can be performed by two different methods:
Method Overloading
Method Overriding
Method overloading is defined as a process that can create multiple methods of the same name in the same class, and all the methods work in different ways. Method overloading occurs when there is more than one method of the same name in the class.
class Shapes {
public void area() {
System.out.println("Find area ");
}
public void area(int r) {
System.out.println("Circle area = "+3.14*r*r);
}
public void area(double b, double h) {
System.out.println("Triangle area="+0.5*b*h);
}
public void area(int l, int b) {
System.out.println("Rectangle area="+l*b);
}
}
public class TestShape {
public static void main(String[] args) {
Shapes myShape = new Shapes(); // Create a Shapes object
myShape.area();
myShape.area(5);
myShape.area(6.0,1.2);
myShape.area(6,2);
}
}
The output will be:
Find area
Circle area = 78.5
Triangle area=3.5999999999999996
Rectangle area=12
public class Addition {
void sum(int a, int b) {
int c = a+b;
System.out.println("Addition of two numbers :" +c);
}
void sum(int a, int b, int e) {
int c = a+b+e;
System.out.println("Addition of three numbers :" +c);
}
public static void main(String[] args) {
Addition obj = new Addition();
obj.sum ( 30,90);
obj.sum(45, 80, 22);
}
}
The output will be:
Addition of two numbers :120
Addition of three numbers :147
Method overriding is defined as a process when the subclass or a child class has the same method as declared in the parent class.
// Vehicle class - superclass
class Vehicle{
//defining a method
void run(){
System.out.println("Vehicle is moving");
}
}
//Class Car2 inherits Vehicle class
class Cars extends Vehicle{
//defining the same method as in the parent class
void run(){
System.out.println("car is running safely");
}
public static void main(String args[]){
Cars obj = new Cars();//creating object
obj.run();//calling method
}
}
The output will be:
car is running safely
Consider the following example. Suppose there are many kinds of shapes, such as triangle, rectangle and so on. We should design a superclass called Shape, which defines the public interfaces (or behaviors) of all the shapes. For example, we would like all the shapes to have a method called getArea(), which returns the area of that particular shape.
/**
* Superclass Shape maintain the common properties of all shapes
*/
public class Shape {
// Private member variable
private String color;
/** Constructs a Shape instance with the given color */
public Shape (String color) {
this.color = color;
}
/** Returns a self-descriptive string */
@Override
public String toString() {
return "Shape[color=" + color + "]";
}
/** All shapes must provide a method called getArea() */
public double getArea() {
// We have a problem here!
// We need to return some value to compile the program.
System.err.println("Shape unknown! Cannot compute area!");
return 0;
}
}
/**
* The Rectangle class, subclass of Shape
*/
public class Rectangle extends Shape {
// Private member variables
private int length, width;
/** Constructs a Rectangle instance with the given color, length and width */
public Rectangle(String color, int length, int width) {
super(color);
this.length = length;
this.width = width;
}
/** Returns a self-descriptive string */
@Override
public String toString() {
return "Rectangle[length=" + length + ",width=" + width + "," + super.toString() + "]";
}
/** Override the inherited getArea() to provide the proper implementation for rectangle */
@Override
public double getArea() {
return length*width;
}
}
/**
* The Triangle class, subclass of Shape
*/
public class Triangle extends Shape {
// Private member variables
private int base, height;
/** Constructs a Triangle instance with the given color, base and height */
public Triangle(String color, int base, int height) {
super(color);
this.base = base;
this.height = height;
}
/** Returns a self-descriptive string */
@Override
public String toString() {
return "Triangle[base=" + base + ",height=" + height + "," + super.toString() + "]";
}
/** Override the inherited getArea() to provide the proper implementation for triangle */
@Override
public double getArea() {
return 0.5*base*height;
}
}
/**
* A test driver for Shape and its subclasses
*/
public class TestShape {
public static void main(String[] args) {
Shape s1 = new Rectangle("red", 4, 5); // Upcast
System.out.println(s1); // Run Rectangle's toString()
System.out.println("Area is " + s1.getArea()); // Run Rectangle's getArea()
System.out.println();
Shape s2 = new Triangle("blue", 4, 5); // Upcast
System.out.println(s2); // Run Triangle's toString()
System.out.println("Area is " + s2.getArea()); // Run Triangle's getArea()
}
}
The output will be like:
Rectangle[length=4,width=5,Shape[color=red]]
Area is 20.0
Triangle[base=4,height=5,Shape[color=blue]]
Area is 10.0
- It is useful for code reusability: reuse attributes and methods of an existing class when you create a new class.