Introduction
In this lesson, we delve into an essential concept of object-oriented programming known as Polymorphism in Java. Understanding polymorphism is crucial for enhancing flexibility and reusability in your code. Here, we will define polymorphism, explore its significance in Java, and distinguish between compile-time and runtime polymorphism. Additionally, we will implement method overloading and overriding to demonstrate these concepts in action.
What is Polymorphism?
Polymorphism in Java allows methods to do different things based on the object that it is acting upon, even if the method name remains the same. This feature is pivotal in achieving flexibility and the ability to define a single interface to represent various underlying forms (data types).
Significance of Polymorphism in Java
- Code Reusability: Write methods that operate on general types rather than specific types, making it easier to add new features.
- Flexibility: Allows the implementation of more generic, extensible code.
- Maintainability: Code becomes easier to maintain and update as logic can be modified in one place rather than in multiple locations.
Compile-Time vs Runtime Polymorphism
Compile-Time Polymorphism
Compile-time polymorphism, also known as static polymorphism, is achieved through method overloading. The compiler determines the method to invoke based on the method signature, i.e., the method name and parameter types.
Example of Method Overloading:
class OverloadExample {
/* Overloaded method for adding two integers */
int add(int a, int b) {
return a + b;
}
/* Overloaded method for adding three integers */
int add(int a, int b, int c) {
return a + b + c;
}
}
class Main {
public static void main(String[] args) {
OverloadExample obj = new OverloadExample();
System.out.println("Sum of 2 numbers: " + obj.add(10, 20)); // Calls add(int, int)
System.out.println("Sum of 3 numbers: " + obj.add(10, 20, 30)); // Calls add(int, int, int)
}
}
Output:
Sum of 2 numbers: 30
Sum of 3 numbers: 60
This example showcases method overloading by defining two methods named add, each with different parameter lists.
Runtime Polymorphism
Runtime polymorphism is achieved through method overriding, where a subclass provides a specific implementation of a method already defined in its superclass. Here, the method that gets executed is resolved at runtime based on the object type, rather than the reference type.
Example of Method Overriding:
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
void sound() {
System.out.println("Cat meows");
}
}
class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Animal reference but Dog object
Animal myCat = new Cat(); // Animal reference but Cat object
myDog.sound(); // Calls the Dog's sound method
myCat.sound(); // Calls the Cat's sound method
}
}
Output:
Dog barks
Cat meows
In this example, sound() is overridden in both Dog and Cat classes. The correct method is called based on the object instance that invokes it.
Practical Applications of Polymorphism
Polymorphism provides powerful ways to create extensible and maintainable code. Consider an application in a graphic editing software:
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
void draw() {
System.out.println("Drawing Circle");
}
}
class Rectangle extends Shape {
void draw() {
System.out.println("Drawing Rectangle");
}
}
class Main {
public static void main(String[] args) {
Shape shape1 = new Circle();
Shape shape2 = new Rectangle();
shape1.draw(); // Outputs: Drawing Circle
shape2.draw(); // Outputs: Drawing Rectangle
}
}
Output:
Drawing Circle
Drawing Rectangle
Here, different Shape types are handled using a common interface, showcasing how polymorphism promotes clean programming.
Summary / Key Takeaways
In this lesson on Polymorphism in Java, you have learned:
- Definition of Polymorphism: Key concept enabling a single method to behave differently based on the object type.
- Compile-Time Polymorphism: Achieved through method overloading, with examples provided.
- Runtime Polymorphism: Produced by method overriding, facilitating dynamic method resolution.
- Code Reusability and Flexibility: Polymorphism enhances application design, improving maintainability.
- Practical Real-World Example: Illustrated the use of polymorphism in manipulating shapes in graphical applications.