Concrete vs. Abstract Classes

As you learn to construct class libraries, you will discover pretty quickly that you can often ‘push’ a number of common attributes and/or methods up the inheritance hierarchy.

For example, the Employee class would typically be used to contain the attributes and methods that are common to all employees, such as name, employee id, telephone number, etc.

However, you might decide that Employee isn’t sufficiently concrete enough to represent a real employee. In practice, an employee usually has a specific role in an organization — an employee is always a Secretary, Programmer, ManagerJanitorPresidentCEOFinancialAnalyst or whatever.

Instantiating an Employee might not actually make sense; it’s not sufficiently concrete — it’s too abstract; we would need to know what kind of Employee we’re talking about.

But the class Employee is still very useful! It allows you to distill out the essence of all employees — those attributes and behaviors that all (or perhaps most) employees share. When you do pull shared attributes and behaviors into a class such as this, it can make the design of the subclasses of that class much cleaner, and can allow you to reuse code more effectively.

A class like this — one that you never expect to instantiate (create instances of) alone; one that is considered incomplete — is called an abstract class.

Abstract Methods

Let’s imagine that we know that all employees will have a raiseSalary() method (else we wouldn’t keep those employees very long!). However, it may well be that each class of employee has his or her salary raised using a different algorithm. We don’t know what that algorithm is when we create the Employee class , but we know that every employee will have one.

We can define the raiseSalary() method on the Employee class, but not actually implement it there.

To do this, we have to declare the method abstract:

public abstract void raiseSalary(double byPercent);

In other words, an abstract method:

  • uses the abstract keyword, and
  • has a declaration, but no implementation.

Abstract Classes

However, a class with one or more abstract methods must itself be declared abstract:

public abstract class Employee
{
    public abstract void raiseSalary(double byPercent);
    // ...
}

(The Java compiler will remind you if you forget!)

An abstract method promises that all non-abstract subclasses of this class will implement that abstract method.

Abstract methods act as placeholders for methods to be implemented in the subclasses.

A class contains abstract methods if any of the following is true:

  • It explicitly contains a declaration of an abstract method
  • It inherits an abstract method from its direct superclass, but does not implement that method.
  • “A direct superinterface of the class declares or inherits a method and the class neither declares it nor inherits a method that implements it. “
    (See later)

Only abstract classes may contain abstract methods. If a class contains abstract methods, but is not declared abstract, then a compile-time error occurs.

The Methods of Abstract Classes

Abstract classes do not have to contain only abstract methods. They may contain a mixture of abstract and concrete methods — and in fact, usually do.

It is a good idea to push as much functionality as possible (as appropriate to that class) into the more abstract classes — it allows you to reuse code more easily.

You may declare a class to be abstract, even if it does not contain any abstract methods. This prevents the class from being instantiated.