Java abstract keyword: abstract classes and methods
Learn how the java abstract keyword works, how to declare abstract classes and methods, and when to use them in your Java design.
The java abstract keyword marks a class or method that cannot be fully implemented at its level of the hierarchy. When applied to a class, it prevents direct instantiation. When applied to a method, it requires every concrete subclass to provide an implementation. This article explains both uses, shows how they fit together, and clarifies the design decisions behind them.
Declaring an Abstract Class
An abstract class is declared by placing the abstract modifier before class. This tells the compiler that the class is incomplete and may contain abstract methods. You cannot create an instance of an abstract class with new. Instead, you must subclass it and provide implementations for any abstract methods.
public abstract class Shape { private String color; public Shape(String color) { this.color = color; } public String getColor() { return color; } public abstract double area(); }
The Shape class declares a concrete field color, a constructor, a concrete getter, and an abstract method area(). The abstract method has no body; it only establishes a contract that subclasses must fulfill. Because Shape is abstract, it cannot be instantiated directly, even though it has a constructor and concrete methods.
Abstract Methods and Their Contract
An abstract method is a method declaration without a body. It forces every concrete subclass to override the method with a real implementation. If a subclass does not implement all inherited abstract methods, that subclass must also be declared abstract.
Consider a concrete subclass:
public class Circle extends Shape { private double radius; public Circle(String color, double radius) { super(color); this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; } }
The Circle class provides an implementation for area(). The @Override annotation is optional but recommended because it lets the compiler verify that the method actually overrides an abstract or concrete method from the superclass. If you forget to implement area(), the compiler will reject Circle unless you declare it abstract as well.
How Abstract Classes Differ from Interfaces
Both abstract classes and interfaces can define abstract methods, but they serve different purposes. The most important difference is that an abstract class can hold state (fields) and have constructors, while an interface cannot (until Java 8 introduced default methods, but even then interfaces cannot have instance fields).
| Feature | Abstract Class | Interface |
|---|---|---|
| Instance fields | Yes | No (only static final constants) |
| Constructors | Yes | No |
| Method implementations | Can have concrete methods | Can have default/static methods |
| Multiple inheritance | A class can extend only one | A class can implement many |
| Access modifiers | All | Public (since Java 9, private methods allowed) |
Use an abstract class when you need to share code and state among closely related classes. Use an interface when you want to define a capability that can be implemented by unrelated classes. For example, Shape is a natural abstract class because all shapes share a color and need an area calculation. Comparable is a better interface because many unrelated types can be compared.
When to Use an Abstract Class
An abstract class is the right choice when you have a group of classes that share a common structure and behavior. The classic example is a template method pattern, where the abstract class defines the skeleton of an algorithm and lets subclasses fill in specific steps.
public abstract class DataParser { public final void parse(String filePath) { String data = readFile(filePath); String parsed = parseData(data); saveResult(parsed); } protected abstract String readFile(String path); protected abstract String parseData(String data); protected abstract void saveResult(String result); }
Here, the parse method is concrete and final, so the algorithm order cannot change. Subclasses only need to implement the three abstract steps. This keeps the workflow in one place and prevents duplication across different file formats.
You should also prefer an abstract class when you need non-public methods or fields that are shared by subclasses. An interface cannot provide protected members, so if you need to expose a protected helper method to subclasses, an abstract class is the only option.
Common Mistakes with the Abstract Keyword
One frequent error is trying to instantiate an abstract class. The compiler rejects new Shape("red") because Shape is abstract. Another mistake is forgetting to implement an abstract method in a concrete subclass. The compiler reports an error like "Circle is not abstract and does not override abstract method area() in Shape".
A subtler mistake is overusing abstract classes. If you have no shared state or concrete methods, an interface is usually more flexible because it allows multiple inheritance of type. Forcing an abstract class hierarchy when an interface would suffice couples classes unnecessarily and makes testing harder.
Another issue is declaring a method abstract when it could have a meaningful default implementation. If most subclasses will implement the same behavior, provide a concrete method instead and let subclasses override it only when needed. This reduces boilerplate and makes the hierarchy easier to extend.
Abstract Classes and Constructors
Abstract classes can have constructors, and those constructors are called when a subclass instance is created. The subclass constructor must explicitly call a superclass constructor using super(...), or the compiler will insert a call to the no-argument constructor if one exists. This allows the abstract class to initialize its own fields before the subclass constructor runs.
public abstract class Base { protected final String name; public Base(String name) { this.name = name; } } public class Derived extends Base { public Derived(String name) { super(name); // required if Base has no no-arg constructor } }
The constructor in an abstract class is not used to instantiate the abstract class directly; it is a mechanism for subclass initialization. This is a common source of confusion because developers expect abstract classes to have no constructors at all.
Maintainability and Design Tradeoffs
Abstract classes are a form of inheritance, and inheritance introduces tight coupling between a superclass and its subclasses. Changes to an abstract class can ripple through the entire hierarchy. For example, adding a new abstract method forces every concrete subclass to implement it, which can be disruptive if the hierarchy is large.
To keep the design maintainable, limit the depth of abstract class hierarchies. Prefer shallow hierarchies with clear responsibilities. If you find yourself adding many abstract methods that are unrelated, consider splitting the responsibilities into separate interfaces. Also, favor composition over inheritance when the relationship is not a true "is-a". An abstract class should model a genuine common type, not just a way to reuse code.
From a runtime perspective, abstract classes have no inherent performance penalty compared to concrete classes. The JVM handles method calls through the same virtual dispatch mechanism. The cost is in design flexibility: a class can extend only one abstract class, so choosing an abstract class consumes the single-inheritance slot. Make that choice deliberately, based on whether shared state and non-public behavior are essential.