Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Abstract classes

Some classes make no sense as objects on their own. A "shape in general" cannot calculate its area — only a circle or a square can. Abstract classes exist for such general ideas.

An abstract method

A method marked abstract is declared but not implemented: it has no body, only a header and a semicolon. A class with such a method is marked abstract too, and subclasses must provide the implementation:

abstract class Shape {
    abstract double area();
}
 
class Square extends Shape {
    double side;
 
    Square(double side) {
        this.side = side;
    }
 
    @Override
    double area() {
        return side * side;
    }
}
 
void main() {
    Shape shape = new Square(4);
    IO.println(shape.area());
}

Output:

16.0

Shared code in an abstract class

An abstract class can contain ordinary methods as well. They use the abstract ones, and the subclass supplies the implementation:

abstract class Shape {
    abstract double area();
 
    String describe() {
        return "A shape with area " + area();
    }
}
 
class Rectangle extends Shape {
    double width;
    double height;
 
    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
 
    @Override
    double area() {
        return width * height;
    }
}
 
void main() {
    IO.println(new Rectangle(2, 3).describe());
}

Output:

A shape with area 6.0

The describe() method is written once, yet it works for any future shape.

Fields and a constructor

An abstract class may have fields and a constructor. You cannot create its object directly, but the constructor is called from a subclass with super(...):

abstract class Employee {
    protected String name;
 
    Employee(String name) {
        this.name = name;
    }
 
    abstract double salary();
 
    String info() {
        return name + ": " + salary() + " €";
    }
}
 
class Developer extends Employee {
    Developer(String name) {
        super(name);
    }
 
    @Override
    double salary() {
        return 4000;
    }
}
 
class Intern extends Employee {
    Intern(String name) {
        super(name);
    }
 
    @Override
    double salary() {
        return 1200;
    }
}
 
void main() {
    Employee[] team = { new Developer("Anna"), new Intern("Oleg") };
    for (Employee e : team) {
        IO.println(e.info());
    }
}

Output:

Anna: 4000.0 €
Oleg: 1200.0 €

A subclass must implement everything

If a subclass has not implemented at least one abstract method, it must be abstract too. Otherwise the compiler reports an error and names the missing method:

abstract class Shape {
    abstract double area();
}
 
class Circle extends Shape {
}
 
void main() {
}

Output:

Main.java:5: error: Main.Circle is not abstract and does not override abstract method area() in Main.Shape
class Circle extends Shape {
^

When to choose an abstract class

An abstract class fits when related classes share fields and code, and only some steps differ. If there is no shared code and you only need to describe a set of methods, an interface is a better fit — that is the next lesson.

Common mistake

You cannot create an object of an abstract class — it has methods without an implementation:

abstract class Shape {
    abstract double area();
}
 
void main() {
    Shape shape = new Shape();
}

Output:

Main.java:6: error: Main.Shape is abstract; cannot be instantiated
    Shape shape = new Shape();
                  ^

Create an object of a concrete subclass; the variable itself can stay of type Shape.

Thanks for reading!

Donate to the site — we work hard for you.