Java Abstract Classes and Interfaces
Abstraction is one of the four pillars of object-oriented programming. It aims to hide complex implementation details and expose only the necessary functionality to users. In Java, abstraction is primarily achieved through two mechanisms: Abstract Classes and Interfaces.
Abstract Class
An abstract class is a class that cannot be instantiated and serves as a parent class (base class) for other classes. It's used to define a general template for a type, which can include some already implemented concrete methods and some abstract methods that must be implemented by subclasses.
- Use the
abstractkeyword to declare an abstract class. - An abstract class can contain instance variables, constructors, concrete methods (with a body), and abstract methods.
- Abstract method: Has only a method signature with no body, declared using the
abstractkeyword. Any subclass that inherits an abstract class must implement all of its abstract methods, unless that subclass itself is also an abstract class.
// 1. Define an abstract class
abstract class Shape {
private String color;
// Abstract classes can have constructors, primarily for subclasses to call
public Shape(String color) {
this.color = color;
}
// This is a concrete method
public String getColor() {
return color;
}
// This is an abstract method, no body
public abstract double getArea();
}
// 2. Create a subclass that extends the abstract class
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color); // Call parent class constructor
this.radius = radius;
}
// 3. Must implement all abstract methods of the parent class
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
public class Main {
public static void main(String[] args) {
// Shape myShape = new Shape("Red"); // Compile error! Cannot instantiate abstract class
Shape circle = new Circle("Blue", 5.0);
System.out.println("Color: " + circle.getColor());
System.out.println("Area: " + circle.getArea());
}
}Interface
An interface is a completely abstract reference type that defines a set of methods (behavioral contract). Any class that implements the interface must provide concrete implementations for these methods. Interfaces are a way to achieve multiple inheritance.
- Use the
interfacekeyword to declare an interface. - All methods in an interface are
public abstractby default (before Java 8). - All variables in an interface are
public static finalby default (i.e., constants). - A class uses the
implementskeyword to implement one or more interfaces.
// 1. Define an interface
interface Playable {
// public static final is automatically added
int MAX_VOLUME = 100;
// public abstract is automatically added
void play();
void stop();
}
// 2. Create a class that implements the interface
class MusicPlayer implements Playable {
@Override
public void play() {
System.out.println("Music starts playing...");
}
@Override
public void stop() {
System.out.println("Music stopped.");
}
}
// Another class implements the same interface
class VideoPlayer implements Playable {
@Override
public void play() {
System.out.println("Video starts playing...");
}
@Override
public void stop() {
System.out.println("Video stopped.");
}
}Java 8+ Interface Enhancements
Starting from Java 8, interfaces can contain default methods and static methods, adding more flexibility to interfaces.
- Default method (
defaultmethod): Allows providing a default implementation for a method in an interface. Classes implementing the interface can use the default version without overriding it. - Static method (
staticmethod): Belongs to the interface itself and can only be called through the interface name.
interface Loggable {
// Abstract method
void log(String message);
// Default method
default void logInfo(String message) {
log("[INFO] " + message);
}
// Static method
static String getLoggerName() {
return "DefaultLogger";
}
}Abstract Class vs. Interface
| Feature | Abstract Class | Interface |
|---|---|---|
| Purpose | Define a general template for a type, achieve code reuse | Define a behavioral contract, specify class capabilities |
| Inheritance | Subclasses use extends keyword, single inheritance in Java | Implementing classes use implements keyword, a class can implement multiple interfaces |
| Member Variables | Can contain any type of member variables (instance, static) | Can only contain public static final constants |
| Constructors | Can have constructors | Cannot have constructors |
| Methods | Can contain abstract and concrete methods | Only abstract methods before Java 8, can have default and static methods after |
| Relationship | "is-a" relationship, emphasizes essence | "has-a" or "can-do" relationship, emphasizes capability |
When to Use?
- Use abstract class: When you want to create a base class that contains common code and state shared by subclasses. When there's a clear hierarchy and "is-a" relationship between classes (e.g.,
Dogis anAnimal). - Use interface: When you want to define a role or capability that can be possessed by classes at different hierarchies. When you want a class to have multiple unrelated behaviors (e.g., a
Birdclass can implement bothFlyableandSingableinterfaces).