Abstraction is a fundamental concept in object-oriented programming that refers to hiding implementation details and exposing only essential functionality. Java provides two primary mechanisms to achieve abstraction – abstract classes and interfaces. While both are used to define generic behaviors for subclasses/implementing classes, there are some notable differences between abstract classes and interfaces in Java.
In this comprehensive guide, we‘ll explore abstract classes and interfaces in depth with examples, see how they are similar and different, understand when to use each, and illustrate their usage with real-world examples. Whether you‘re a beginner learning Java abstractions or an experienced developer looking to deepen your knowledge, this guide will help you master abstract classes and interfaces in Java.
Abstract Classes in Java
An abstract class in Java is a class that cannot be instantiated directly and may contain abstract methods. Abstract methods only have a method signature and no body. Abstract classes are used to provide common implementations for subclasses to reuse while allowing subclasses to have different implementations through abstract methods.
Let‘s dig deeper into abstract classes in Java:
Declaring Abstract Classes
To declare a class abstract in Java, you simply use the abstract keyword before the class keyword:
public abstract class AbstractClass {
// abstract class code
}
This prevents direct instantiation with new AbstractClass(). The class must be extended.
Abstract and Concrete Methods
An abstract class can contain both abstract and concrete (regular) methods:
public abstract class AbstractClass {
// Concrete method
public void concreteMethod() {
System.out.println("Concrete method");
}
// Abstract method
public abstract void abstractMethod();
}
The abstract methods must be implemented in subclasses, while concrete methods can be inherited as-is.
Inheriting from Abstract Classes
Any subclass of an abstract class must implement all of its abstract methods, either by overriding them or by being declared abstract itself.
For example:
public abstract class AbstractClass {
public abstract void abstractMethod1();
public abstract void abstractMethod2();
}
public class ConcreteClass extends AbstractClass {
@Override
public void abstractMethod1() {
// implementation
}
@Override
public void abstractMethod2() {
// implementation
}
}
Here ConcreteClass overrides both abstract methods, so it‘s concrete. But if it didn‘t implement them, it would also need to be declared abstract.
Characteristics of Abstract Classes
These are some key characteristics and capabilities of abstract classes in Java:
- Cannot be instantiated directly
- Can have constructors, static methods and static variables
- Allowed to have final, non-final, static and non-static members
- Can have implemented methods to share common code
- Can implement interfaces and have access modifiers on members
- Faster execution than interfaces
In summary, abstract classes allow defining generic behaviors through abstract methods while providing member variables and implemented methods for reuse in subclasses.
Abstract Class Example
Let‘s look at an example abstract class representing a geometric shape:
public abstract class Shape {
private String color;
public Shape(String color) {
this.color = color;
}
public abstract double area();
public abstract double perimeter();
public String getColor() {
return color;
}
}
Shape defines the common color attribute and enforces the area() and perimeter() behaviors through abstract methods. Subclasses like Circle and Rectangle can extend Shape and implement these methods based on their specific shape while reusing the color attribute and getter.
This enables polymorphic code like:
Shape shape = new Circle("Red");
System.out.println(shape.area());
The Shape reference allows working with different kinds of shapes generically.
Interfaces in Java
An interface in Java provides full abstraction and specifies behaviors that implementing classes must define. It‘s like a completely abstract class with no concrete members. Interfaces are useful for:
- Defining APIs and contracts
- Decoupling implementations from usages
- Allowing classes to support multiple interfaces
- Future proofing by allowing new interfaces
Let‘s explore Java interfaces more:
Declaring Interfaces
Interfaces are declared using the interface keyword:
public interface InterfaceExample {
void abstractMethod1();
void abstractMethod2();
}
Implementing Interfaces
A class uses the implements keyword to implement an interface:
public class ImplementingClass implements InterfaceExample {
@Override
public void abstractMethod1() {
// implementation
}
@Override
public void abstractMethod2() {
// implementation
}
}
All interface methods must be implemented concretely.
Characteristics of Interfaces
These are some key properties of interfaces in Java:
- Cannot be instantiated directly, just like abstract classes
- Can only contain abstract method declarations, no concrete methods
- Methods are implicitly
publicin interfaces - Can have
staticandfinalvariables - Allows multiple inheritance – a class can implement multiple interfaces
Interface Example
Let‘s look at an example Driveable car interface:
public interface Driveable {
void start();
void stop();
void accelerate();
}
A car class can implement this interface:
public class Car implements Driveable {
@Override
public void start() {
// start engine
}
@Override
public void stop() {
// stop engine
}
@Override
public void accelerate() {
// accelerate car
}
}
This enforces that Car must implement the driving capabilities defined in Driveable. And we can rely on that contract in our code.
Similarities between Abstract Classes and Interfaces
While abstract classes and interfaces have many differences, there are two core similarities between them:
No Instantiation
Firstly, neither abstract classes nor interfaces can be instantiated directly. They must be extended and implemented by concrete subclasses respectively.
Polymorphism
Secondly, they both support polymorphism in Java. You can use an abstract class or interface reference to point to concrete subclass/implementing class objects at runtime:
AbstractClass obj = new ConcreteClass();
InterfaceExample obj = new ImplementingClass();
This allows abstract types to define generic behaviors leveraged via polymorphism.
Differences between Abstract Classes and Interfaces
While abstract classes and interfaces have some similarities, there are also notable differences between the two. Let‘s compare them:
| Criterion | Abstract Class | Interface |
|---|---|---|
| Inheritance | Single inheritance only | Multiple inheritance allowed |
| Member Variables | Can have state and non-static members | Only static and final variables |
| Member Methods | Can have implemented concrete methods | Cannot have any method bodies |
| Access Modifiers | Has access modifiers on methods | Interface methods are public by default |
| Constructors | Can define constructors | Cannot define constructors |
| Execution | Faster execution | Slower execution |
Let‘s examine some key differences:
Inheritance
A class can only inherit from one abstract class in Java while a class can implement multiple interfaces. Interfaces promote greater flexibility and allow behaviors from multiple sources.
Member Variables
Abstract classes can have member variables that maintain state across instances. Interfaces can only have static and final variables that act more like constants.
Member Methods
Abstract classes allow defining implemented concrete methods that subclasses inherit. Interfaces can only have abstract method signatures with no implementation code.
Access Modifiers
Access modifiers like public, protected can be applied on abstract class methods. Interface methods are always implicitly public.
Constructors
Constructors defined in an abstract class are inherited in subclasses. But interfaces cannot define constructors since they cannot be instantiated.
Execution Speed
Abstract classes have faster execution speed than interfaces in Java. This is because interfaces use dynamic dispatch to invoke methods at runtime.
So in summary, there are many design differences between abstract classes and interfaces that impact how they are used for abstraction in Java.
When to Use Abstract Classes vs Interfaces
When should you use an abstract class and when should you use an interface in Java? Here are some guidelines:
Consider an Abstract Class when:
- You need to share implementation between subclasses
- You want to define reusable member variables and methods
- You need to maintain state across the class hierarchy
- You want to declare non-public members
- You need to define constructors, static methods etc.
For example, abstract classes are commonly used to provide skeletal implementations for collections like AbstractList, AbstractSet, AbstractMap etc.
Consider an Interface when:
- You expect unrelated classes to implement your interface
- You want to define a functionality contract but don‘t care about implementation details
- Your classes need to implement multiple interfaces
- You want loose coupling between classes
- You need to allow adding new interfaces in the future
For example, Java interfaces like Runnable, Serializable, Comparable define contracts without knowing about concrete classes.
Real-World Example
Let‘s look at a real-world example of choosing between an abstract class and interface from the Java Collections Framework:
List is defined as an interface while AbstractList provides a skeletal implementation as an abstract class:
public interface List<E> {
// List methods
}
public abstract class AbstractList<E> implements List<E> {
// Implement common List methods
}
public class ArrayList<E> extends AbstractList<E> {
// ArrayList implementation
}
This allows ArrayList to inherit common List functionality from AbstractList while also being able to implement other interfaces like Serializable.
Conclusion
We‘ve explored abstract classes and interfaces in depth and seen how they achieve abstraction in Java through commonalities and differences:
- Use abstract classes to define reusable code templates for subclasses
- Use interfaces to define contracts for unrelated classes to implement
- Understand their inheritance, methods, variables, and performance trade-offs
- Choose between them based on requirements like code reuse vs flexibility
Mastering abstraction with abstract classes and interfaces is critical for effective Java programming. Use this guide to make the right decisions in your designs and better leverage abstraction in your code.
I hope you found this guide helpful! Let me know if you have any other questions.