Performance of Java 'final': methods calls on a final vs non-final class
As discussed on the first page, a common
misconception about final is that it is useful as a performance
optimisation. On this page, I will present some data illustrating that this isn't
actually the case.
In the test, we take a class called BaseClass
which defines a particular method, doOperaton().
Then, we create three types of classes that extend BaseClass, and
override doOperation(), as follows:
- non-final classes that extend BaseClass but which,
despite the potential to be extended, are not then themselves extended;
- final classes that extend BaseClass;
- extended classes: that is, non-final classes which themselves
extend BaseBlass, and for which there also exists another extending
class— in other words, there is a hierarchy BaseClass <
ExtnededBaseClass < ExtendedExtendedBaseClass, but
the class that we actually call a method on is the middle one in this
hierarchy.
We then consider calling a class from all three categories non-final (but
not extended), final and extended, in one of two cases.
In the first
case, the JVM cannot predict what what precise subclass of BaseClass the
call is being made on. We define a method as follows:
private static int doTestRun(List<BaseClass> l) {
int ret = 0;
for (BaseClass c : l) {
ret += c.doOperation();
}
return ret;
}
This method is then called with a list of instances whose precise class is
chosen at random (e.g. FinalClassA or FinalClassB, although the
classes in a given list are always of the same category (non-final, final or extended).
In the second case, the JVM can predict which precise subclass we make the
call on. We define a method such as the following, where the precise subclass is specified
in the method signature and so can be known by the compiler:
private static int doTestRunClassFinalA(List<ClassFinalA> l) {
int ret = 0;
for (ClassFinalA c : l) {
ret += c.doOperation();
}
return ret;
}
We thus have six different tests, comprising the combinations of
category (non-final, final, extended) and whether or not the precise subclass is known
to the compiler.
On the next page, we look at the results of these tests, which show us
the timings of
final vs non-final and of knwon
vs unknown subclass.