In Java, the final keyword can be applied to instance, static, and local variables — but each behaves a little differently once you add it. This post walks through what changes for each of the three, with the compile-time errors you'll actually see if you get it wrong.
Final Instance Variable
- If the value of a variable changes from object to object, such a variable is called an instance variable.
- For every object, a separate copy of the instance variable will be created.
- Instance variables do not require explicit initialization; JVM always provides default values.
class Test {
int x; // instance variable
public static void main(String... args) {
Test t = new Test();
System.out.println(t.x); // output: 0
}
}
- If the instance variable is declared as final, then explicit initialization is mandatory. JVM will NOT provide default values.
class Test {
final int x;
}
Compile-time Error: variable x might not have been initialized.
Rule: A final instance variable must be initialized before constructor completion.Possible places for initialization
1. At the time of declaration
class Test {
final int x = 10;
}
2. Inside an instance block
class Test {
final int x;
{
x = 10;
}
}
3. Inside the constructor
class Test {
final int x;
Test() {
x = 10;
}
}
These are the only valid places for initialization. Assigning anywhere else results in an error.
Invalid Example:
class Test {
final int x;
public static void m() {
x = 10; // Invalid
}
}
Compile-time Error: cannot assign a value to final variable x.
Final Static Variables
If a variable's value does not vary from object to object, it should be declared at the class level using the static modifier.
Static variables have a single copy shared among all objects and are automatically given default values by the JVM.
Example:
class Test {
static int x;
public static void main(String... args) {
System.out.println(x); // output: 0
}
}
If a static variable is declared as final, then explicit initialization is mandatory.
Example:
class Test {
final static int x;
}
Compile-time Error: variable x might not have been initialized.
Rule: A final static variable must be initialized before class loading completes.Possible places for initialization
1. At the time of declaration
class Test {
final static int x = 10;
}
2. Inside a static block
class Test {
final static int x;
static {
x = 10;
}
}
These are the only valid places. Assigning anywhere else causes an error.
Invalid Example:
class Test {
final static int x;
public void m() {
x = 10; // Invalid
}
}
Compile-time Error: cannot assign a value to final variable x.
Final Local Variables
If a variable is declared inside a method, constructor, or block, it is called a local variable.
- Local variables must be initialized explicitly before use; the JVM does not provide default values.
- If a local variable is declared as final, its value cannot be changed once assigned.
class Test {
public static void main(String... args) {
final int x;
x = 10;
System.out.println(x); // output: 10
}
}
Rule: A final local variable can be assigned only once, and it must be assigned before it is used.
Invalid Example:
class Test {
public static void main(String... args) {
final int x = 10;
x = 20; // Invalid, cannot reassign
System.out.println(x);
}
}
Compile-time Error: cannot assign a value to final variable x.
Another Invalid Example (used before assignment):
class Test {
public static void main(String... args) {
final int x;
System.out.println(x); // Invalid, x not yet assigned
x = 10;
}
}
Compile-time Error: variable x might not have been initialized.
Note: Unlike final instance and static variables, a final local variable does not need to be initialized at the time of declaration — but it must be assigned exactly once before it is read, and it cannot be reassigned afterward.
Conclusion
The core idea stays the same across all three: once you mark a variable final, the JVM stops giving you a free default value, and you become responsible for initializing it exactly once, in one of a small set of allowed places. Where those allowed places are is what differs:
- Instance: declaration, instance block, or constructor — must be done before the constructor finishes.
- Static: declaration or static block — must be done before class loading completes.
- Local: anywhere in the method, as long as it happens exactly once, before the variable is read.
Get the initialization timing right, and final becomes a simple, useful way to guarantee a value never changes after it's set.
0 Comments