final

8.1.2.2 final Classes

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.

13.4.2 final Classes

If 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.

8.3.1.2 final Fields

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.

In the example:


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.

8.4.3.3 final Methods

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.