Chapter 26: Exploring Polymorphism and the Abstract Keyword in Java
Introduction
In this post, we'll dive into two core concepts of Object-Oriented Programming (OOP) in Java: Polymorphism and the Abstract Keyword. These features provide flexibility and reusability to our code, allowing us to create robust and scalable applications.
1. Understanding Polymorphism in Java
Polymorphism allows objects to be treated as instances of their parent class rather than their actual class. This ability supports dynamic method dispatch or method overriding, enabling runtime decisions on which method to execute.
Types of Polymorphism:
Compile-Time Polymorphism (Method Overloading)
- Occurs when multiple methods share the same name but differ in parameters (type, number, or order).
class MathOperations {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
MathOperations math = new MathOperations();
System.out.println("Integer addition: " + math.add(5, 10)); // Output: 15
System.out.println("Double addition: " + math.add(5.5, 10.5)); // Output: 16.0
}
}
Runtime Polymorphism (Method Overriding)
- Achieved when a subclass overrides a method of its superclass, allowing specific implementations depending on the object instance.
class Animal {
void sound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Woof");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Polymorphism
myDog.sound(); // Output: Woof
}
}
2. Abstract Keyword in Java
The abstract keyword in Java is used to declare abstract classes and abstract methods. Abstract classes allow defining methods that subclasses must implement, creating a template for subclasses.
Key Characteristics:
Abstract Classes cannot be instantiated directly.
Abstract Methods lack a body and are declared with the
abstract
keyword. Subclasses must implement these methods unless they are also abstract.
Example of Abstract Class and Abstract Method:
Let's create an abstract class Shape
and concrete subclasses Circle
and Rectangle
.
abstract class Shape {
abstract void draw(); // Abstract method
void description() { // Concrete method
System.out.println("This is a shape.");
}
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Circle");
}
}
class Rectangle extends Shape {
@Override
void draw() {
System.out.println("Drawing a Rectangle");
}
}
public class Main {
public static void main(String[] args) {
Shape circle = new Circle();
Shape rectangle = new Rectangle();
circle.draw(); // Output: Drawing a Circle
rectangle.draw(); // Output: Drawing a Rectangle
circle.description(); // Output: This is a shape.
}
}
3. Combining Abstract Classes and Polymorphism
In practice, abstract classes and polymorphism are often used together to achieve loose coupling and extendibility. This enables flexible code design where new classes can be introduced without altering the existing logic significantly.
Example: Animal Class with Polymorphism and Abstract Method
abstract class Animal {
abstract void sound();
void sleep() {
System.out.println("This animal sleeps.");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Meow");
}
}
class Cow extends Animal {
@Override
void sound() {
System.out.println("Moo");
}
}
public class Zoo {
public static void main(String[] args) {
Animal cat = new Cat();
Animal cow = new Cow();
cat.sound(); // Output: Meow
cow.sound(); // Output: Moo
cat.sleep(); // Output: This animal sleeps.
}
}
In this example, sound()
is implemented differently for each animal type, showcasing polymorphism. This setup allows adding new animals by simply extending the Animal
class and implementing the sound()
method.
4. Benefits of Using Abstract Classes and Polymorphism Together
Code Reusability: Shared methods in the abstract class reduce redundant code across subclasses.
Scalability: New functionalities can be added through inheritance without changing existing code.
Flexibility: Different subclasses can provide specific implementations for abstract methods, promoting modular code.
5. Summary and Best Practices
Use abstract classes when a class needs to provide a common template with some methods for subclasses.
Apply polymorphism to enable dynamic method invocation, making code adaptable for future requirements.
Avoid instantiating abstract classes directly; use them as a blueprint for subclasses.
Conclusion
Understanding Polymorphism and Abstract Classes equips you with powerful tools in Java to write more structured and adaptable code. By effectively using these principles, you can make your Java applications more maintainable and flexible.