Abstraction
In short: Show only the “what” to the outside, not the “how” — a class or interface defines which operations are possible without revealing their concrete implementation.
In more detail: Java implements abstraction via two mechanisms: abstract class (can contain both finished and open, still-to-be-implemented methods, but cannot be instantiated directly itself) and interface (pure contract definition with no state of its own). Both force subclasses to concretely implement the open methods.
In Depth
The core idea: contract instead of implementation
Abstraction is one of the four core principles of OOP (alongside encapsulation, inheritance, and polymorphism) and answers the question: “What does the user of a class need to know to use it?” — no more than necessary. A List, for example, promises “add elements, retrieve them by index”, regardless of whether an ArrayList (array-based, fast random access) or LinkedList (linked nodes, faster insertion in the middle) is behind it. Calling code doesn’t need to know the internal implementation and can swap it out without being changed itself — which is why variables are typically declared as List<T> list = new ArrayList<>(); instead of ArrayList<T> list = new ArrayList<>();, to preserve exactly this interchangeability in your own code.
abstract class: shared code plus open points
abstract class is suitable when subclasses should share common code (e.g. a base implementation), but you still want to force individual methods:
abstract class Shape {
abstract double area(); // must be implemented - no method body
void describe() { // shared, finished code - the same for ALL subclasses
System.out.println("Area: " + area());
}
}
class Circle extends Shape {
double radius;
Circle(double radius) { this.radius = radius; }
@Override
double area() { return Math.PI * radius * radius; }
}
class Rectangle extends Shape {
double width, height;
Rectangle(double width, double height) { this.width = width; this.height = height; }
@Override
double area() { return width * height; }
}An abstract class CANNOT be instantiated directly (new Shape() doesn’t compile) — it exists only to be extended by concrete subclasses. If a class contains even ONE abstract method, the entire class itself must be marked abstract, even if it otherwise only contains finished code.
interface: pure contract across class hierarchies
An interface, by contrast, traditionally only defines the contract, with no state of its own (fields — apart from static final constants) and no implementation. Since Java 8, however, default methods with a default implementation are also allowed, which blurs the boundary with the abstract class somewhat:
interface Flying {
void fly();
default void land() { // default implementation, overridable
System.out.println("Landing initiated");
}
}
interface Swimming {
void swim();
}
// A class can implement any number of interfaces
class Duck implements Flying, Swimming {
public void fly() { System.out.println("Duck flies"); }
public void swim() { System.out.println("Duck swims"); }
}Rule of thumb for choosing
abstract class for an “is-a” relationship with shared state and shared base logic (e.g. Shape → Circle, Rectangle), interface for a “can-do-X” across independent class hierarchies — a Duck can simultaneously be Flying and Swimming, even though both abilities have nothing to do with each other conceptually. The decisive technical difference: a class can implement any number of interfaces, but can only inherit from EXACTLY ONE class (Java has no multiple inheritance of classes, to avoid the so-called “diamond problem” ambiguity that C++ has to solve with its multiple inheritance).
Distinction from Encapsulation
Abstraction is often confused with encapsulation, because both somehow have to do with “hiding” — the difference: abstraction hides complexity at the design level (which methods exist, not how they’re implemented), encapsulation hides concrete state at the implementation level (private fields with getters/setters). A class can be perfectly encapsulated (all fields private) and still be poorly abstracted (too many, too specific public methods that reveal internal details).
See also: Interface, OOP, Encapsulation, Polymorphism, Classes