SyntaxStudy
Sign Up
Java Abstract Classes vs Concrete Classes
Java Beginner 1 min read

Abstract Classes vs Concrete Classes

An abstract class is a class declared with the abstract modifier that cannot be instantiated directly. It serves as a template for subclasses and may contain a mix of abstract methods (without a body, which subclasses must implement) and concrete methods (with a body, which subclasses inherit). Abstract classes can also have constructors, fields, and static members. Abstract classes are appropriate when several related classes share common state and partial implementation. For example, a Vehicle abstract class might provide an engine field, a start method, and an abstract method travel that each subclass (Car, Truck, Motorcycle) implements differently. The Template Method design pattern formalises this: the abstract class defines the skeleton of an algorithm in a concrete method, calling abstract steps that subclasses fill in. Concrete classes provide implementations for all inherited abstract methods and can be instantiated. When extending an abstract class, the subclass must implement every abstract method or itself be declared abstract. Trying to instantiate an abstract class or a class that still has unimplemented abstract methods is a compile-time error.
Example
// Abstract class using Template Method pattern
abstract class DataProcessor {

    // Template method: defines the algorithm skeleton
    public final void process(String data) {
        String validated = validate(data);      // step 1
        String transformed = transform(validated); // step 2 (abstract)
        store(transformed);                     // step 3 (abstract)
        System.out.println("Processing complete.");
    }

    // Concrete shared step
    protected String validate(String data) {
        if (data == null || data.isBlank())
            throw new IllegalArgumentException("Data must not be blank");
        return data.trim();
    }

    // Abstract steps — subclasses decide how to implement
    protected abstract String transform(String data);
    protected abstract void   store(String data);
}

class UpperCaseFileProcessor extends DataProcessor {
    @Override
    protected String transform(String data) {
        return data.toUpperCase();
    }

    @Override
    protected void store(String data) {
        System.out.println("[FILE] Storing: " + data);
    }
}

class JsonProcessor extends DataProcessor {
    @Override
    protected String transform(String data) {
        return "{\"value\": \"" + data + "\"}";
    }

    @Override
    protected void store(String data) {
        System.out.println("[DB] Inserting JSON: " + data);
    }
}

public class AbstractClassDemo {
    public static void main(String[] args) {
        // new DataProcessor();  // compile error — abstract class

        DataProcessor file = new UpperCaseFileProcessor();
        file.process("  hello world  ");

        System.out.println();

        DataProcessor json = new JsonProcessor();
        json.process("  42  ");
    }
}