A class can be declared final
if its definition is complete and no subclasses are desired or required. A compile-time error occurs if the name of a final
class appears in the extends
clause of another class
declaration; this implies that a final
class cannot have any subclasses. A compile-time error occurs if a class is declared both final
and abstract
, because the implementation of such a class could never be completed.
Because a final
class never has any subclasses, the methods of a final
class are never overridden.
final
ClassesIf a class that was not declared final
is changed to be declared final
, then a VerifyError
is thrown if a binary of a pre-existing subclass of this class is loaded, because final
classes can have no subclasses; such a change is not recommended for widely distributed classes.
Changing a class that was declared final
to no longer be declared final
does not break compatibility with pre-existing binaries.
A field can be declared final
, in which case its declarator must include a variable initializer or a compile-time error occurs. Both class and instance variables (static
and non-static
fields) may be declared final
.
Any attempt to assign to a final
field results in a compile-time error. Therefore, once a final
field has been initialized, it always contains the same value. If a final
field holds a reference to an object, then the state of the object may be changed by operations on the object, but the field will always refer to the same object. This applies also to arrays, because arrays are objects; if a final
field holds a reference to an array, then the components of the array may be changed by operations on the array, but the field will always refer to the same array.
Declaring a field final
can serve as useful documentation that its value will not change, can help to avoid programming errors, and can make it easier for a compiler to generate efficient code.
class Point { int x, y; int useCount; Point(int x, int y) { this.x = x; this.y = y; } final static Point origin = new Point(0, 0); }
the class Point
declares a final
class variable origin
. The origin
variable holds a reference to an object that is an instance of class Point
whose coordinates are (0, 0). The value of the variable Point.origin
can never change, so it always refers to the same Point
object, the one created by its initializer. However, an operation on this Point
object might change its state-for example, modifying its useCount
or even, misleadingly, its x
or y
coordinate.
A method can be declared final
to prevent subclasses from overriding or hiding it. It is a compile-time error to attempt to override or hide a final
method.
A private
method and all methods declared in a final
class are implicitly final
, because it is impossible to override them. It is permitted but not required for the declarations of such methods to redundantly include the final
keyword.
It is a compile-time error for a final
method to be declared abstract
.
At run-time, a machine-code generator or optimizer can easily and safely "inline" the body of a final
method, replacing an invocation of the method with the code in its body, as in the example:
final class Point { int x, y; void move(int dx, int dy) { x += dx; y += dy; } }
class Test { public static void main(String[] args) { Point[] p = new Point[100]; for (int i = 0; i < p.length; i++) { p[i] = new Point(); p[i].move(i, p.length-1-i); } } }
Here, inlining the method move
of class Point
in method main
would transform the for
loop to the form:
for (int i = 0; i < p.length; i++) { p[i] = new Point(); Point pi = p[i]; pi.x += i; pi.y += p.length-1-i; }
The loop might then be subject to further optimizations.
Such inlining cannot be done at compile time unless it can be guaranteed that Test
and Point
will always be recompiled together, so that whenever Point
-and specifically its move
method-changes, the code for Test.main
will also be updated.