Final Methods in Classes
A final method in a class is a concrete method (i.e., has an implementation) and cannot be overridden or hidden in any subclass. Any normal class can declare a final method. The class need not be declared final.
In Example 5.9, the non-final class Light defines the final method setWatts() at (10).
class Light { // (1)
// …
public final void setWatts(int watt) { // (10) Final instance method
noOfWatts = watt;
}
}
The subclass TubeLight attempts to override the final method setWatts() from the superclass Light at (14), which is not permitted.
class TubeLight extends Light { // (12)
// …
@Override
public void setWatts(int watt) { // (14) Cannot override final method at (10)!
noOfWatts = 2*watt;
}
}
A call to a final method is bound at compile time; as such, a method cannot be overridden by a subclass and therefore there is no dynamic lookup to perform at runtime. A method that is declared final allows the compiler to do code optimization by replacing its method call with the code of its method body, a technique called inlining. Use of the final keyword for exceptional performance enhancement is not recommended, as the compiler is too smart to fall for that trick.
A subclass cannot override or hide a private method from its superclass. However, it can define a new method using the same method signature as the private method, without regard to the other criteria for overriding: the return type and the throws clause. Defining a new method using the same method signature is not possible with a final method which cannot be overridden or hidden. Declaring a private method as final in addition is redundant.
Although a constructor cannot be overridden, it also cannot be declared final.
The java.lang.Object class—the superclass of all classes—defines a number of final methods (notify(), notifyAll(), and wait()—mostly to synchronize the running of threads) that all objects inherit, but cannot override.
Example 5.9 Using the final Modifier
import java.util.Arrays;
import static java.lang.System.out;
class Light { // (1)
// Static final variables:
public static final double KWH_PRICE = 3.25; // (2) Constant static variable
public static final String MANUFACTURER; // (3) Blank final static field
static { // Static initializer block
MANUFACTURER = “Ozam”; // (4) Initializes (3)
}
// Instance variables:
int noOfWatts; // (5)
final String color; // (6) Blank final instance field
final String energyRating; // (7) Blank final instance field
{ // Instance initializer block
color = “off white”; // (8) Initializes (6)
}
// Constructor:
Light() {
energyRating = “A++”; // (9) Initializes (7)
}
public final void setWatts(int watt) { // (10) Final instance method
this.noOfWatts = watt;
}
public static void setKWH(double rate) {
// KWH_PRICE = rate; // (11) Not OK. Final field.
}
}
//______________________________________________________________________________
class TubeLight extends Light { // (12)
static StringBuilder color = new StringBuilder(“green”); // (13) Hiding (6)
//@Override
//public void setWatts(int watt) { // (14) Cannot override final method at (10)!
// noOfWatts = 2*watt;
//}
}
//______________________________________________________________________________
public class Warehouse {
public static void main(final String[] args) { // (15) Final parameter
final Light workLight = new Light(); // (16) Non-blank final local variable.
workLight.setWatts(100); // (17) OK. Changing object state.
// workLight.color = “pink”; // (18) Not OK. Final instance field.
// workLight = new Light(); // (19) Not OK. Changing final reference.
final Light alarmLight; // (20) Blank final local variable.
// alarmLight.setWatts(200); // (21) Not OK. Not initialized.
Light carLight; // (22) Non-final local variable.
// carLight.setWatts(10); // (23) Not OK. Not initialized.
out.println(“Accessing final static fields in class Light:”);
out.println(“KWH_PRICE: ” + Light.KWH_PRICE);
out.println(“MANUFACTURER: ” + Light.MANUFACTURER);
out.println(“Accessing final instance fields in an object of class Light:”);
out.println(“noOfWatts: ” + workLight.noOfWatts);
out.println(“color: ” + workLight.color);
out.println(“energyRating: ” + workLight.energyRating);
out.println(“Fun with final parameter args:”);
out.println(Arrays.toString(args)); // Print array.
out.println(“args length: ” + args.length);
args[0] = “1”; // (24) OK. Modifying array state.
out.println(Arrays.toString(args)); // Print array.
// args = null; // (25) Not OK. Final parameter.
// args.length = 10; // (26) Not OK. Final instance field.
}
}
Output from the program when run with the following command:
>
java Warehouse One Two Three
Accessing final static fields in class Light:
KWH_PRICE: 3.25
MANUFACTURER: Ozam
Accessing final instance fields in an object of class Light:
noOfWatts: 100
color: off white
energyRating: A++
Fun with final parameter args:
[One, Two, Three]
args length: 3
[1, Two, Three]