Java Notes
Complete guide to abstract classes in Java — abstract methods, partial implementation, when to use abstract classes, template method pattern, and abstract class vs interface comparison.
An abstract class is a class that cannot be instantiated directly and may contain abstract methods (methods without a body). It serves as a blueprint for subclasses — providing partial implementation while forcing subclasses to complete the rest.
Think of it as a recipe with some steps filled in and others left blank: "First, preheat the oven. Then, prepare the filling (you decide how). Finally, bake for 30 minutes."
Declaring an Abstract Class
public abstract class Shape {
// Concrete fields
protected String color;
protected String name;
// Constructor (cannot instantiate, but subclasses use it)
public Shape(String name, String color) {
this.name = name;
this.color = color;
}
// Abstract methods — NO body, subclass MUST implement
public abstract double area();
public abstract double perimeter();
// Concrete methods — shared implementation, inherited as-is
public void displayInfo() {
System.out.printf("%s %s | Area: %.2f | Perimeter: %.2f%n",
color, name, area(), perimeter());
}
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
}
// ❌ Cannot instantiate abstract class
// Shape shape = new Shape("test", "red"); // COMPILE ERROR!
// ✅ Must create concrete subclass
public class Circle extends Shape {
private double radius;
public Circle(double radius, String color) {
super("Circle", color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}
public class Rectangle extends Shape {
private double width, height;
public Rectangle(double width, double height, String color) {
super("Rectangle", color);
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
}
public class Main {
public static void main(String[] args) {
Shape[] shapes = {
new Circle(5, "Red"),
new Rectangle(4, 6, "Blue"),
new Circle(3, "Green")
};
for (Shape s : shapes) {
s.displayInfo();
}
}
}Red Circle | Area: 78.54 | Perimeter: 31.42 Blue Rectangle | Area: 24.00 | Perimeter: 20.00 Green Circle | Area: 28.27 | Perimeter: 18.85
Rules of Abstract Classes
| Rule | Description |
|---|---|
| Cannot instantiate | new AbstractClass() is a compile error |
| Can have constructors | Used by subclass via super() |
| Can have abstract methods | No body, just declaration |
| Can have concrete methods | Regular methods with full implementation |
| Can have fields | Instance variables, static variables, constants |
| Subclass must implement all abstract methods | Unless subclass is also abstract |
Can have static methods | Called on the class directly |
Can have final methods | Cannot be overridden by subclass |
Cannot be final | final abstract is contradictory |
Template Method Pattern
The most important use of abstract classes — define the algorithm skeleton, let subclasses fill in specific steps:
Reading CSV file: users.csv Parsed 3 CSV rows === REPORT === Analyzed 3 records ============== Fetching JSON from API: https://api.example.com/users Parsed 2 JSON objects === REPORT === Deep analysis of 2 JSON records: All valid ==============
Abstract Class with Complete Example
public abstract class Animal {
protected String name;
protected int age;
protected double weight;
public Animal(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
// Abstract - each animal makes different sounds
public abstract String makeSound();
// Abstract - each animal moves differently
public abstract String movementType();
// Concrete - all animals can be described
public void describe() {
System.out.println("--- " + getClass().getSimpleName() + " ---");
System.out.println("Name: " + name);
System.out.println("Age: " + age + " years");
System.out.println("Weight: " + weight + " kg");
System.out.println("Sound: " + makeSound());
System.out.println("Movement: " + movementType());
System.out.println("Daily food: " + calculateFood() + " kg");
}
// Concrete with default logic (can be overridden)
public double calculateFood() {
return weight * 0.03; // 3% of body weight
}
}
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, double weight, String breed) {
super(name, age, weight);
this.breed = breed;
}
@Override
public String makeSound() { return "Woof! Woof!"; }
@Override
public String movementType() { return "Running on 4 legs"; }
@Override
public double calculateFood() {
// Dogs need more food relative to weight
return weight * 0.04;
}
}
public class Eagle extends Animal {
private double wingspan;
public Eagle(String name, int age, double weight, double wingspan) {
super(name, age, weight);
this.wingspan = wingspan;
}
@Override
public String makeSound() { return "Screeeech!"; }
@Override
public String movementType() { return "Flying (wingspan: " + wingspan + "m)"; }
}
public class Fish extends Animal {
private String waterType;
public Fish(String name, int age, double weight, String waterType) {
super(name, age, weight);
this.waterType = waterType;
}
@Override
public String makeSound() { return "Blub blub"; }
@Override
public String movementType() { return "Swimming in " + waterType + " water"; }
@Override
public double calculateFood() {
return weight * 0.02; // Fish eat less
}
}
public class Main {
public static void main(String[] args) {
Animal[] zoo = {
new Dog("Rex", 5, 30, "German Shepherd"),
new Eagle("Liberty", 8, 4.5, 2.1),
new Fish("Nemo", 2, 0.1, "saltwater")
};
for (Animal animal : zoo) {
animal.describe();
System.out.println();
}
}
}--- Dog --- Name: Rex Age: 5 years Weight: 30.0 kg Sound: Woof! Woof! Movement: Running on 4 legs Daily food: 1.2 kg --- Eagle --- Name: Liberty Age: 8 years Weight: 4.5 kg Sound: Screeeech! Movement: Flying (wingspan: 2.1m) Daily food: 0.135 kg --- Fish --- Name: Nemo Age: 2 years Weight: 0.1 kg Sound: Blub blub Movement: Swimming in saltwater water Daily food: 0.002 kg
Abstract Class vs Interface
| Feature | Abstract Class | Interface |
|---|---|---|
| Instantiation | Cannot | Cannot |
| Abstract methods | Can have | All methods (pre-Java 8) |
| Concrete methods | Can have | default and static (Java 8+) |
| Fields | Any type (instance, static) | Only public static final (constants) |
| Constructors | Can have | Cannot |
| Access modifiers | Any | public (methods are public by default) |
| Inheritance | Single (extends one class) | Multiple (implements many) |
| When to use | Shared state + partial behavior | Pure contract/capability |
Use Abstract Class When:
- Subclasses share common state (fields)
- You need constructors
- You want to provide default behavior with
protectedaccess - The relationship is genuinely IS-A
Use Interface When:
- Defining a capability or contract
- Multiple classes from different hierarchies need the same behavior
- You want multiple inheritance
- You want maximum flexibility
Common Mistakes
- Trying to instantiate an abstract class:
``java Shape s = new Shape("test", "red"); // ❌ Compile error! ``
- Forgetting to implement all abstract methods:
``java public class Square extends Shape { @Override public double area() { return side * side; } // ❌ Missing perimeter() — compile error unless Square is also abstract } ``
- Making abstract class final:
``java public final abstract class Shape { } // ❌ Contradictory! // final = can't extend, abstract = must extend ``
- Abstract methods with body:
``java public abstract void draw() { // ❌ Abstract methods cannot have body System.out.println("drawing"); } ``
- Abstract methods being private:
``java private abstract void helper(); // ❌ Private can't be overridden! ``
Best Practices
- Use the Template Method pattern — define algorithm skeleton in abstract class
- Keep abstract classes focused — one clear responsibility
- Provide meaningful default implementations where possible
- Use
protectedfor methods subclasses might need - Consider combining abstract class + interface for maximum flexibility
- Document what subclasses must provide and what they get for free
Interview Questions
Q1: Can an abstract class have a constructor? Yes. The constructor is called by subclasses via super(). It initializes the abstract class's fields.
Q2: Can an abstract class have no abstract methods? Yes. It's valid — it simply can't be instantiated. Useful to prevent direct instantiation of a base class.
Q3: Can you create a reference variable of an abstract class type? Yes. Shape s = new Circle(5, "Red"); — the reference type is abstract, but it points to a concrete object.
Q4: If a class has one abstract method, must the class be abstract? Yes. Any class with at least one abstract method MUST be declared abstract.
Q5: What happens if a subclass doesn't implement all abstract methods? The subclass must also be declared abstract. Eventually, a concrete class in the hierarchy must implement all remaining abstract methods.
Q6: Can abstract methods be static? No. Static methods belong to the class and are resolved at compile time. Abstract methods need runtime resolution (polymorphism).
Q7: When would you choose an abstract class over an interface? When subclasses share state (fields) and you want to provide partial implementation. When you need constructors. When some methods should be protected.
Q8: Can an abstract class have a constructor? Why? Yes. Although you can't instantiate an abstract class directly, its constructor is called when a concrete subclass is created (via super()). The constructor initializes the abstract class's fields and sets up the parent portion of the object.
Q9: What happens if a class extends an abstract class but doesn't implement all abstract methods? The class must also be declared abstract. Only when ALL abstract methods are implemented can the class be concrete (non-abstract). This creates a chain: AbstractA → AbstractB (adds some) → ConcreteC (implements all remaining).
Q10: What is the Template Method Pattern with abstract classes? Template Method defines the skeleton of an algorithm in a base abstract class, with specific steps as abstract methods that subclasses must implement. Example: DataProcessor has process() calling validate(), transform(), save() — subclasses provide specific implementations.
Q11: Can we have an abstract class with no abstract methods? Yes. It's valid and prevents direct instantiation while providing common functionality. This is useful when a class shouldn't be instantiated but all methods have default implementations. The abstract keyword just prevents new AbstractClass().
Q12: When should you choose abstract class over interface? Use abstract class when: (1) you need to share code among related classes, (2) you need non-public members, (3) you need constructors, (4) you want to declare non-static/non-final fields. Use interface when: unrelated classes need common capability, you want multiple inheritance.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Abstract Class in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, oops, abstract, class
Related Java Master Course Topics