Java Core: Inheritance and Polymorphism - Interfaces and Abstract Classes
This document outlines the concepts of Interfaces and Abstract Classes in Java, crucial for understanding inheritance and polymorphism.
1. Abstract Classes
What is an Abstract Class?
An abstract class is a class that cannot be instantiated directly. It's designed to be a blueprint for other classes. It can contain both abstract and concrete (fully implemented) methods.
Key Characteristics:
abstractkeyword: Declared using theabstractkeyword.public abstract class MyAbstractClass { ... }- Abstract Methods: Methods declared without a body (implementation). They must be implemented by concrete subclasses.
public abstract void myMethod(); - Concrete Methods: Methods with a full implementation. Subclasses can use these directly or override them.
- Can have constructors: Although you can't create instances of an abstract class, constructors are used by subclasses during initialization.
- Can have instance variables: Abstract classes can hold data.
- Single Inheritance: Java only supports single inheritance for classes. A class can only extend one abstract class.
When to use Abstract Classes:
- Common functionality: When you want to provide a common base for a group of related classes, sharing some common methods and data.
- Partial implementation: When you want to define a template for subclasses, forcing them to implement certain methods while providing some default behavior.
- "Is-a" relationship: Abstract classes represent a more general concept, and subclasses represent more specific types of that concept (e.g.,
Animalis abstract,DogandCatextend it).
Example:
abstract class Shape {
String color;
Shape(String color) {
this.color = color;
}
// Abstract method - must be implemented by subclasses
public abstract double area();
// Concrete method - can be used or overridden
public String getColor() {
return color;
}
}
class Circle extends Shape {
double radius;
Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
double width;
double height;
Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
}
public class AbstractClassExample {
public static void main(String[] args) {
// Shape shape = new Shape(); // Error: Cannot instantiate abstract class
Circle circle = new Circle("Red", 5.0);
Rectangle rectangle = new Rectangle("Blue", 4.0, 6.0);
System.out.println("Circle Area: " + circle.area());
System.out.println("Rectangle Area: " + rectangle.area());
}
}
2. Interfaces
What is an Interface?
An interface is a completely abstract "contract" that specifies a set of methods that a class must implement. It defines what a class should do, but not how it should do it.
Key Characteristics:
interfacekeyword: Declared using theinterfacekeyword.public interface MyInterface { ... }- Abstract Methods (by default): All methods declared in an interface are implicitly
publicandabstract. You don't need to explicitly use these keywords (though you can). - No Instance Variables (until Java 8): Interfaces traditionally couldn't have instance variables (fields). (See Java 8 updates below).
- Multiple Inheritance: A class can implement multiple interfaces. This is a key difference from abstract classes.
- Default Methods (Java 8+): Java 8 introduced the ability to define
defaultmethods in interfaces, providing a default implementation that classes can choose to override. - Static Methods (Java 8+): Java 8 also allows
staticmethods in interfaces. These are called using the interface name (e.g.,MyInterface.staticMethod()). - Private Methods (Java 9+): Java 9 introduced private methods in interfaces to help with code reuse within the interface itself.
When to use Interfaces:
- Defining a role: When you want to define a capability or role that multiple unrelated classes can fulfill (e.g.,
Runnable,Comparable). - Multiple inheritance: When you need a class to exhibit behaviors from multiple sources.
- Loose coupling: Interfaces promote loose coupling between classes, making your code more flexible and maintainable.
- "Can-do" relationship: Interfaces represent a capability that a class can have (e.g., a
BirdcanFly).
Example:
interface Flyable {
void fly(); // Abstract method
}
interface Swimmable {
void swim(); // Abstract method
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying.");
}
@Override
public void swim() {
System.out.println("Duck is swimming.");
}
}
class Fish implements Swimmable {
@Override
public void swim() {
System.out.println("Fish is swimming.");
}
}
public class InterfaceExample {
public static void main(String[] args) {
Duck duck = new Duck();
Fish fish = new Fish();
duck.fly();
duck.swim();
fish.swim();
// fish.fly(); // Error: Fish does not implement Flyable
}
}
Java 8+ Interface Enhancements:
interface MyInterface {
// Abstract method
void abstractMethod();
// Default method (provides a default implementation)
default void defaultMethod() {
System.out.println("Default implementation");
}
// Static method
static void staticMethod() {
System.out.println("Static method in interface");
}
}
3. Abstract Class vs. Interface: Key Differences
| Feature | Abstract Class | Interface |
|---|---|---|
| Keywords | abstract class |
interface |
| Methods | Can have abstract and concrete methods | Traditionally only abstract methods (Java 8+ allows default and static) |
| Instance Variables | Can have instance variables | Traditionally no instance variables (Java 8+ allows private static final variables) |
| Inheritance | Single inheritance (extends only one abstract class) | Multiple inheritance (implements multiple interfaces) |
| "Is-a" vs. "Can-do" | Represents an "is-a" relationship | Represents a "can-do" relationship |
| Implementation | Provides partial implementation | Defines a contract; no implementation (except default methods in Java 8+) |
| Flexibility | Less flexible due to single inheritance | More flexible due to multiple inheritance |
4. Choosing Between Abstract Classes and Interfaces
Use an Abstract Class:
- When you have a clear "is-a" relationship.
- When you want to share some common implementation details among subclasses.
- When you anticipate that the class hierarchy will evolve and require adding more methods in the future.
Use an Interface:
- When you want to define a role or capability that multiple unrelated classes can fulfill.
- When you need multiple inheritance.
- When you want to promote loose coupling and flexibility.
- When you want to define a contract without providing any implementation.
This comprehensive overview should provide a solid understanding of abstract classes and interfaces in Java. Remember to practice with examples to solidify your knowledge.