Abstract Classes


An abstract class is a class marked with the abstract keyword. It, contrary to non-abstract class, may contain abstract - implementation-less - methods. It is, however, valid to create an abstract class without abstract methods.

An abstract class cannot be instantiated. It can be sub-classed (extended) as long as the sub-class is either also abstract, or implements all methods marked as abstract by super classes.

An example of an abstract class:

public abstract class Component {
	private int x, y;
 
	public setPosition(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public abstract void render();
}

The class must be marked abstract, when it has at least one abstract method. An abstract method is a method that has no implementation. Other methods can be declared within an abstract class that have implementation in order to provide common code for any sub-classes.

Attempting to instantiate this class will provide a compile error:

//error: Component is abstract; cannot be instantiated 
Component myComponent = new Component();

However a class that extends Component, and provides an implementation for all of its abstract methods and can be instantiated.

public class Button extends Component {
	@Override
	public void render() {
		//render a button
	}
}
 
public class TextBox extends Component {
	@Override
	public void render() {
		//render a textbox
	}
}

Instances of inheriting classes also can be cast as the parent class (normal inheritance) and they provide a polymorphic effect when the abstract method is called.

Component myButton = new Button();
Component myTextBox = new TextBox();
 
myButton.render(); //renders a button
myTextBox.render(); //renders a text box

Abstract classes vs Interfaces

Abstract classes and interfaces both provide a way to define method signatures while requiring the extending/implementing class to provide the implementation.

There are two key differences between abstract classes and interfaces:

  • A class may only extend a single class, but may implement many interfaces.
  • An abstract class can contain instance (non-static) fields, but interfaces may only contain static fields.
Version < Java SE 8

Methods declared in interfaces could not contain implementations, so abstract classes were used when it was useful to provide additional methods which implementations called the abstract methods.

Version ≥ Java SE 8

Java 8 allows interfaces to contain default methods, usually implemented using the other methods of the interface, making interfaces and abstract classes equally powerful in this regard.

Anonymous subclasses of Abstract Classes

As a convenience java allows for instantiation of anonymous instances of subclasses of abstract classes, which provide implementations for the abstract methods upon creating the new object. Using the above example this could look like this:

Component myAnonymousComponent = new Component() {
	@Override
	public void render() {
		// render a quick 1-time use component
	}
}

Using 'final' to restrict inheritance and overriding

Final classes

When used in a class declaration, the final modifier prevents other classes from being declared that extend the class. A final class is a "leaf" class in the inheritance class hierarchy

// This declares a final class
final class MyFinalClass {
	/* some code */
}
 
// Compilation error: cannot inherit from final MyFinalClass
class MySubClass extends MyFinalClass {
	/* more code */
}

Use-cases for final classes

Final classes can be combined with a private constructor to control or prevent the instantiation of a class. This can be used to create a so-called "utility class" that only defines static members; i.e. constants and static methods.

public final class UtilityClass {
 
	// Private constructor to replace the default visible constructor
	private UtilityClass() {}
 
	// Static members can still be used as usual
	public static int doSomethingCool() {
		return 123;
	}
}

Immutable classes should also be declared as final. (An immutable class is one whose instances cannot be changed after they have been created; see the Immutable Objects topic. ) By doing this, you make it impossible to create a mutable subclass of an immutable class. That would violate the Liskov Substitution Principle which requires that a subtype should obey the "behavioral contract" of its supertypes.

From a practical perspective, declaring an immutable class to be final makes it easier to reason about program behavior. It also addresses security concerns in the scenario where untrusted code is executed in a security sandbox. (For instance, since String is declared as final, a trusted class does not need to worry that it might be tricked into accepting mutable subclass, which the untrusted caller could then surreptitiously change.)

One disadvantage of final classes is that they do not work with some mocking frameworks such as Mockito. Update: Mockito version 2 now support mocking of final classes.

Final methods

The final modifier can also be applied to methods to prevent them being overridden in sub-classes:

public class MyClassWithFinalMethod {
	public final void someMethod() {
	}
}
 
public class MySubClass extends MyClassWithFinalMethod {
	@Override
	public void someMethod() { // Compiler error (overridden method is final)
	}
}

Final methods are typically used when you want to restrict what a subclass can change in a class without forbidding subclasses entirely.

The final modifier can also be applied to variables, but the meaning of final for variables is unrelated to inheritance.

Basic Programs