Wednesday, May 14, 2008

Uses of Final Keyword


Final Variables
A variable can be declared final. A final variable may only be assigned to once. It is a compile time error if a final variable is assigned to unless it is definitely unassigned immediately prior to the assignment.

A blank final is a final variable whose declaration lacks an initializer.


Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.
Declaring a variable final can serve as useful documentation that its value will not change and can help avoid programming errors.
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.
We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression, a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization , binary compatibility and definite assignment .

final Fields
A field can be declared final. Both class and instance variables (static and non-static fields) may be declared final.
It is a compile-time error if a blank final class variable is not definitely assigned by a static initializer of the class in which it is declared.
A blank final instance variable must be definitely assigned at the end of every constructor of the class in which it is declared; otherwise a compile-time error occurs.

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 immediately within a final class behave as if they are final, since it is impossible to override them.
It is a compile-time error for a final method to be declared abstract.
At run time, a machine-code generator or optimizer can "inline" the body of a final method, replacing an invocation of the method with the code in its body. The inlining process must preserve the semantics of the method invocation. In particular, if the target of an instance method invocation is null, then a NullPointerException must be thrown even if the method is inlined. The compiler must ensure that the exception will be thrown at the correct point, so that the actual arguments to the method will be seen to have been evaluated in the correct order prior to the method invocation.
Consider 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];
int j = p.length-1-i;
pi.x += i;
pi.y += j;
}


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.


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.


Stumble
Delicious
Technorati
Twitter

0 Comments:

Post a Comment