Syntax
abstract class ClassName {\n abstract returnType methodName();\n}Examples
Basic Abstract Class
Defining a base class that mixes concrete and abstract methods.
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public abstract void makeSound(); // no body - subclasses must implement
public void sleep() { // concrete method, shared by all subclasses
System.out.println(name + " is sleeping");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " says: Woof!");
}
}
// Animal a = new Animal("Generic"); // Error - can't instantiate abstract class
Dog dog = new Dog("Rex");
dog.makeSound();
dog.sleep();Enforcing a Common Structure
Multiple subclasses implementing the same abstract method differently.
abstract class Employee {
protected String name;
protected double baseSalary;
public Employee(String name, double baseSalary) {
this.name = name;
this.baseSalary = baseSalary;
}
public abstract double calculateBonus();
public double totalPay() {
return baseSalary + calculateBonus();
}
}
class Manager extends Employee {
public Manager(String name, double baseSalary) {
super(name, baseSalary);
}
@Override
public double calculateBonus() {
return baseSalary * 0.2;
}
}
class Developer extends Employee {
public Developer(String name, double baseSalary) {
super(name, baseSalary);
}
@Override
public double calculateBonus() {
return baseSalary * 0.1;
}
}
Employee m = new Manager("John", 60000);
System.out.println(m.totalPay()); // 72000.0Abstract Class vs Interface
A quick illustration of when each is more appropriate.
// Interface: unrelated classes sharing a capability, no shared state
interface Flyable {
void fly();
}
// Abstract class: closely related classes sharing state AND behavior
abstract class Bird {
protected String species;
public Bird(String species) {
this.species = species;
}
public abstract void layEggs();
public void breathe() {
System.out.println(species + " is breathing");
}
}
class Eagle extends Bird implements Flyable {
public Eagle() {
super("Eagle");
}
public void layEggs() {
System.out.println("Eagle laying eggs");
}
public void fly() {
System.out.println("Eagle soaring high");
}
}Best practices
- Use an abstract class when subclasses share both state (fields) and some common implemented behavior, not just a method signature
- Use an interface instead when unrelated classes just need to share a capability, with no shared fields or implementation
- A class can only extend one abstract class but can implement multiple interfaces - factor that into your design choice
- Make a method abstract only when every subclass genuinely needs its own distinct implementation - otherwise provide a sensible default in the abstract class itself
Runtime & versions
Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Java Language Specification