Abstract Classes and Interfaces
After inheritance and polymorphism, an important question appears: how do you describe a common type when some behavior can already be implemented, while some must be left for specific classes to provide? Java has abstract classes and interfaces for this purpose. They help define common rules for different implementations, but they do it in different ways.
An abstract class is a foundation for a family of classes
An abstract class is declared with abstract.
You cannot create its object directly, but it can store state,
have constructors, regular methods, and methods without an implementation — abstract methods.
abstract class Animal {
private String name;
Animal(String name) {
this.name = name;
}
String getName() {
return name;
}
abstract String sound();
}
class Dog extends Animal {
Dog(String name) {
super(name);
}
@Override
String sound() {
return "Woof";
}
}
Animal already has common state and a ready-to-use
getName() method, but the specific sound is not known in advance.
That is why sound() only defines a requirement,
while Dog provides the implementation.
An interface is a contract of capabilities
An interface is useful when what matters is not the common origin of objects,
but what they can do. A class connects an interface with
implements and takes responsibility for fulfilling its contract.
interface Payable {
double calculatePayment();
}
class Freelancer implements Payable {
private double amount;
Freelancer(double amount) {
this.amount = amount;
}
@Override
public double calculatePayment() {
return amount;
}
}
The calculatePayment() method in the interface is declared without a body.
Such a method is implicitly public abstract,
so its implementation in the class must be public.
The interface itself, just like an abstract class, cannot be created with new.
The main advantage of an interface becomes especially clear when one class needs several independent capabilities. A class can extend only one class, but it can implement multiple interfaces.
interface Printable {
void print();
}
interface Scannable {
void scan();
}
class OfficeDevice implements Printable, Scannable {
@Override
public void print() {
System.out.println("Printing");
}
@Override
public void scan() {
System.out.println("Scanning");
}
}
An interface can contain ready-made behavior
An interface is not necessarily just a set of methods without bodies.
A method with the default modifier can have an implementation
that classes receive automatically and can override when necessary.
interface Loggable {
default void log(String message) {
System.out.println(message);
}
}
This makes it possible to add common behavior to a contract without turning the interface into a base class. At the same time, an interface is still not intended to store the ordinary state of each object.
Abstract class or interface?
Use the meaning of the relationship between classes as your guide. An abstract class fits when related objects have a common foundation: state, constructors, and part of a shared implementation. An interface fits when you need to describe a separate capability or contract that can be fulfilled even by classes from different hierarchies.
- Abstract class: “these objects belong to one family and share a common foundation.”
- Interface: “these objects promise to be able to do a particular thing.”
These approaches do not compete with each other. One class can extend an abstract class and implement one or more interfaces at the same time — this is how flexible models are often built in Java.