ADDITIONAL SYSTEM INFORMATION :
OS: Windows 11 Pro (Version 23H2)
Java Version: 25.0.1; Java HotSpot(TM) 64-Bit Server VM
Environment: Standard Desktop PC, no custom JVM flags used during execution.
A DESCRIPTION OF THE PROBLEM :
The issue relates to the visibility of uninitialized final fields during object construction. In Java, a final variable is expected to be observed only after it has been assigned its constant value. However, if a final variable is initialized via a method call (e.g., final int x = getX();), and that method reads the same variable, the JVM returns the default value (0) instead of throwing a compilation error or preventing access.
This behavior allows a 'constant' to be observed in an inconsistent state, breaking the integrity of the final keyword. While direct forward reference is blocked by the compiler, this indirect access via this escape during initialization remains unprotected, leading to potential logic errors in complex class hierarchies.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Environment Setup: Ensure you have the Java Development Kit (JDK) installed (any version, e.g., JDK 11, 17, or 21,24,25).
2.Code Creation: Create a new Java file named BugDemo.java.
3.Code Implementation: Copy and paste the following code into the file:
class BugDemo {
// Step 1: Initialize a final variable using a method call
final int x = this.getX();
int getX() {
// Step 2: Print the value of 'x' inside the method during its own initialization
System.out.println("Value of x during getX(): " + x);
return 10;
}
public static void main(String[] args) {
// Step 3: Instantiate the class
new BugDemo();
}
}
4. Compilation: Open the terminal and compile the class using:
javac BugDemo.java
5. Execution: Run the compiled class using:
java BugDemo
6. Observation: Observe the output in the console.
---------- BEGIN SOURCE ----------
class BugDemo {
final int x = this.getX();
int getX() {
// Accessing 'x' before it is initialized
System.out.println(x + " via get function");
return 10;
}
BugDemo() {
System.out.println(this.x + " via constructor");
}
public static void main(String[] args) {
new BugDemo();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
To avoid observing a final variable in its uninitialized state, developers should:
1. Avoid Method Calls in Field Initializers: Directly assign values to final fields instead of using methods that might leak the uninitialized this reference.
2.Use Constructor Parameters: Pass the required value directly through the constructor.
3.Refactor to Lazy Initialization: Use a getter method with a local check to ensure the value is set before use.
safe code:
class SafeDemo {
final int x;
SafeDemo() {
this.x = 10; // Assigning directly in constructor
System.out.println(this.x + " via constructor");
}
Description: The issue is a loophole in the Java initialization sequence where this escapes during field assignment, allowing a final variable to be read before its final value is committed. [2]
Workaround: Avoid calling instance methods that access final fields during their own initialization. [3]
System Info: Windows 11, Java 25.0.1.
Confidential Info: None.
FREQUENCY :
ALWAYS
OS: Windows 11 Pro (Version 23H2)
Java Version: 25.0.1; Java HotSpot(TM) 64-Bit Server VM
Environment: Standard Desktop PC, no custom JVM flags used during execution.
A DESCRIPTION OF THE PROBLEM :
The issue relates to the visibility of uninitialized final fields during object construction. In Java, a final variable is expected to be observed only after it has been assigned its constant value. However, if a final variable is initialized via a method call (e.g., final int x = getX();), and that method reads the same variable, the JVM returns the default value (0) instead of throwing a compilation error or preventing access.
This behavior allows a 'constant' to be observed in an inconsistent state, breaking the integrity of the final keyword. While direct forward reference is blocked by the compiler, this indirect access via this escape during initialization remains unprotected, leading to potential logic errors in complex class hierarchies.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Environment Setup: Ensure you have the Java Development Kit (JDK) installed (any version, e.g., JDK 11, 17, or 21,24,25).
2.Code Creation: Create a new Java file named BugDemo.java.
3.Code Implementation: Copy and paste the following code into the file:
class BugDemo {
// Step 1: Initialize a final variable using a method call
final int x = this.getX();
int getX() {
// Step 2: Print the value of 'x' inside the method during its own initialization
System.out.println("Value of x during getX(): " + x);
return 10;
}
public static void main(String[] args) {
// Step 3: Instantiate the class
new BugDemo();
}
}
4. Compilation: Open the terminal and compile the class using:
javac BugDemo.java
5. Execution: Run the compiled class using:
java BugDemo
6. Observation: Observe the output in the console.
---------- BEGIN SOURCE ----------
class BugDemo {
final int x = this.getX();
int getX() {
// Accessing 'x' before it is initialized
System.out.println(x + " via get function");
return 10;
}
BugDemo() {
System.out.println(this.x + " via constructor");
}
public static void main(String[] args) {
new BugDemo();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
To avoid observing a final variable in its uninitialized state, developers should:
1. Avoid Method Calls in Field Initializers: Directly assign values to final fields instead of using methods that might leak the uninitialized this reference.
2.Use Constructor Parameters: Pass the required value directly through the constructor.
3.Refactor to Lazy Initialization: Use a getter method with a local check to ensure the value is set before use.
safe code:
class SafeDemo {
final int x;
SafeDemo() {
this.x = 10; // Assigning directly in constructor
System.out.println(this.x + " via constructor");
}
Description: The issue is a loophole in the Java initialization sequence where this escapes during field assignment, allowing a final variable to be read before its final value is committed. [2]
Workaround: Avoid calling instance methods that access final fields during their own initialization. [3]
System Info: Windows 11, Java 25.0.1.
Confidential Info: None.
FREQUENCY :
ALWAYS