The Java final keyword
The Java final keyword is very loosely used to indicate that something "cannot change".
Specifically— and perhaps confusingly from a language
design point of view— it has a number of uses:
- it is used to indicate that a class cannot be extended;
- it is used to indicate that a method cannot be overridden;
- it is used to indicate that a local variable cannot be changed once its value
is set;
- it is used to indicate that a static variable cannot be changed once set,
in effect implementing "constants";
- it is used to indicate that a value of an instance variable cannot
be changed once set; this (due to an amendment to the JVM specification as of
Java 5) makes accesses to that
variable thread safe.
A common misconception about the Java final keyword is that it is essentially
a performance optimisation. In Java, final is much more about program design than performance, as we illustrate later when we look at some timings
relating to the performance of final
as a class modifier.
Using final to indicate that a class or method cannot be overridden
You can use final to specify that a whole class may not be extended, or similarly
that a method cannot be overridden.
So when would you use final in this way? A common case is where:
- a particular method that you are implementing needs to be public (e.g. because it extends
some base class that requires it to be public, or simply because you expect callers from
outside the package to call it)...
- ...but you want classes that extend your class not to override your public method, because
it contains some logic that you don't want replacing.
As an example, imagine if we were implementing a template for a
swing component which would have a number of subclasses,
but whose subclasses would always need to draw content on the "left" and "right" side
of the component, at specific coordinates. We would probably therefore implement our template
component as a subclass of JComponent,
requiring a public paintComponent() method:
public abstract class LeftAndRightComponent extends JComponent {
...
public void paintComponent(Graphics g) {
// calculate x and y for left side
...
paintLeftSide(x, y);
// calculate x and y for right side
...
paintRightSide(x, y);
}
protected abstract void paintLeftSide(int x, int y);
protected abstract void paintRightSide(int x, int y);
}
But now we have the problem that overriding classes, as well as implementing
paintLeftSide() and paintRightSide(), could "accidentally"
override paintComponent() itself, in effect removing the whole
functionality of the class! The solution is to declare this method final:
public abstract class LeftAndRightComponent extends JComponent {
...
public final void paintComponent(Graphics g) {
...
paintLeftSide(x, y);
...
paintRightSide(x, y);
}
...
}
Now, a subclass can still override paintLeftSide() and paintRightSide(),
but not paintComponent, which is declared final.
Final classes
Cases for making an entire class final are less common, but would essentially
be where allowing a subclass with differing implementation
could lad to unexpected behaviour.
A notable example from the JDK itself is the String class. A central
design decision of Java strings is that they are immutable, and some of the inner workings
of strings are tightly coupled with internals of the JVM itself. These factors together
mean that allowing subclasses of String could lead to some unexpected behaviour,
and so the String class is defined as being final:
public final class String {
...
}