Final Methods in Classes – Object-Oriented Programming

Final Methods in Classes – Object-Oriented Programming

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

Click here to view code image

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.

Click here to view code image

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

Click here to view code image

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:

Click here to view code image

>
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]