Abstract Class in Java
An abstract class in Java is a parent class that's deliberately left unfinished. It shares common code with its subclasses but leaves some methods for each subclass to fill in. You can't create an object of an abstract class directly. This guide shows how abstract classes work, the rules, and when to choose one over an interface.
What is an abstract class in Java?
Think of a form with some fields pre-filled and others left blank. Every copy shares the pre-filled parts, but each person must complete the blanks before it's valid. An abstract class is that form: the shared code is written once, and the blanks are abstract methods.
public abstract class Notification {
private final String recipient;
protected Notification(String recipient) {
this.recipient = recipient;
}
// Shared, finished behaviour
public void send(String message) {
System.out.println("Sending to " + recipient + " via " + channel());
deliver(message);
}
// The "blanks" each subclass must fill in
protected abstract String channel();
protected abstract void deliver(String message);
} abstract class— marks the class as unfinished;new Notification(...)is not allowed.protected abstract void deliver(...)— an abstract method: a signature with no body, ending in a semicolon.send(...)— a normal method. Every subclass inherits it as-is.
Let's see it in action: extending an abstract class
Each subclass fills in the blanks in its own way:
public class EmailNotification extends Notification {
public EmailNotification(String address) {
super(address);
}
@Override
protected String channel() { return "email"; }
@Override
protected void deliver(String message) {
System.out.println(" [SMTP] " + message);
}
}
public class SmsNotification extends Notification {
public SmsNotification(String phone) {
super(phone);
}
@Override
protected String channel() { return "SMS"; }
@Override
protected void deliver(String message) {
String shortMsg = message.length() > 22 ? message.substring(0, 22) + "…" : message;
System.out.println(" [SMS] " + shortMsg);
}
} Notification[] alerts = {
new EmailNotification("asha@example.com"),
new SmsNotification("+94 77 123 4567")
};
for (Notification n : alerts) {
n.send("Your order has shipped and will arrive Friday");
} Sending to asha@example.com via email [SMTP] Your order has shipped and will arrive Friday Sending to +94 77 123 4567 via SMS [SMS] Your order has shipped…
The loop treats both objects as a plain Notification, yet each one behaves differently. The shared
send() logic was written once. This pattern, where a parent defines the steps and children fill
in the details, is called the template method pattern.
What are the rules for abstract classes?
| Rule | Allowed? |
|---|---|
Create an object with new AbstractClass() | ✘ No (compile error) |
Declare a variable of the abstract type: Notification n = ... | ✔ Yes |
| Have constructors | ✔ Yes (called via super(...)) |
| Have fields, static methods, and normal methods | ✔ Yes |
| Have zero abstract methods | ✔ Yes |
| Have an abstract method in a non-abstract class | ✘ No |
Mark an abstract method private, static, or final | ✘ No |
Mark the class both abstract and final | ✘ No (they contradict each other) |
What if a subclass doesn't implement every abstract method?
Then that subclass must also be declared abstract. Only a class that fills in all the
blanks is "concrete" and can be created with new.
Abstract class vs interface in Java
This is one of the most common Java interview questions. Here's the practical difference:
| Abstract class | Interface | |
|---|---|---|
| A class can use… | Only one (extends) | Many (implements) |
| Instance fields (state) | ✔ Yes | ✘ No (constants only) |
| Constructors | ✔ Yes | ✘ No |
| Methods with code | ✔ Yes | ✔ Yes (default, static, private) |
| Member visibility | Any access modifier | Public (plus private helpers) |
| Best describes | "is a" — a family of closely related classes | "can do" — a capability, like Comparable |
Rule of thumb: start with an interface. Reach for an abstract class when several related classes need to share state (fields) or constructor logic. You can also combine them: an abstract class can implement an interface and provide a partial implementation.
Where do you see abstract classes in real Java code?
java.util.AbstractList— implement justget()andsize()and you get a working read-only List.java.io.InputStream— subclasses only have to implement the single-byteread()method.- Framework base classes, such as
HttpServletin Jakarta EE, which you extend and override.
Quick recap
- An abstract class can't be instantiated; it's meant to be extended.
- Abstract methods have no body; concrete subclasses must implement all of them.
- Abstract classes can have fields, constructors, and finished methods.
- A class can extend one abstract class but implement many interfaces.
What's next?
Learn the more flexible alternative in Java interfaces, or revisit how inheritance in Java works.
Frequently Asked Questions
What is an abstract class in Java?
An abstract class is a class marked with the abstract keyword that can't be turned into an object directly. It acts as a partly finished parent: it can contain normal code that subclasses share, plus abstract methods that each subclass must fill in.
Can an abstract class have a constructor?
Yes. You can't call it with new directly, but it runs whenever a subclass object is created, through super(...). It's typically used to set up fields that every subclass shares.
Can an abstract class have no abstract methods?
Yes. A class can be declared abstract even with zero abstract methods. This is a way of saying 'this class is only meant to be extended, never created on its own'.
What is the difference between an abstract class and an interface?
An abstract class can hold instance fields and constructors, and a class can extend only one. An interface can't hold instance state, but a class can implement many. Use an abstract class for closely related classes sharing code, and an interface for a capability many unrelated classes can have.
Can an abstract method be private, static, or final?
No. An abstract method must be overridden by a subclass, and private, static, and final methods can't be overridden. Combining abstract with any of them is a compile error.