JDK-7004835 : Different handling for final in constructor
  • Type: Bug
  • Component: specification
  • Sub-Component: language
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2010-12-06
  • Updated: 2018-06-11
  • Resolved: 2011-07-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 rcFixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.6.2) (suse-0.1-x86_64)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux xxx 2.6.25.20-0.7-default #1 SMP 2010-02-26 20:32:57 +0100 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
There is a different handling for final member in constructor: Accessing by this or without this lead to a compile error or does not.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
/tmp/java> javac FinalClass.java
/tmp/java> java FinalClass foo
before init : this.s == null
after init : this.s == foo
/tmp/java> javac FinalClass2.java
FinalClass2.java:5: variable s might not have been initialized
if (s != null) {
^
1 error
/tmp/java>

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I'd prefer to get a compile error for FinalClass, too. But according to http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.5.2 neither should lead to a compile error.

ACTUAL -
FinalClass is compilable, FinalClass2 is not

ERROR MESSAGES/STACK TRACES THAT OCCUR :
FinalClass2.java:5: variable s might not have been initialized
if (s != null) {
^
1 error

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class FinalClass {
private final String s;

public FinalClass(String ss) {
if (this.s != null) {
System.out.println("before init\t: this.s != null : " + this.s);
} else {
System.out.println("before init\t: this.s == null");
}
this.s = ss;
System.out.println("after init\t: this.s == " + this.s);
}

public static void main(String[] args) {
new FinalClass(args[0]);
}
}


#######################################

public class FinalClass2 {
private final String s;

public FinalClass2(String ss) {
if (s != null) {
System.out.println("before init\t: this.s != null : " + this.s);
} else {
System.out.println("before init\t: this.s == null");
}
this.s = ss;
System.out.println("after init\t: this.s == " + this.s);
}

public static void main(String[] args) {
new FinalClass2(args[0]);
}
}

---------- END SOURCE ----------

Comments
EVALUATION Technically, JLS3 says only FinalClass2 ('s') is illegal, while FinalClass ('this.s') is legal. This is because access to the value of a blank final field "consists of the simple name of the variable occurring anywhere in an expression except as...". Assignment, however, occurs "if either the simple name of the variable, or its simple name qualified by this, occurs on the LHS of an assignment operator". The disparity between access and assignment was formalized only in JLS3. It looks undesirable; 'this.s' and 's' in the body of a constructor unquestionably refer to the same field of the enclosing class, and DU/DA is ultimately about fields not variables. (Whether either expression yields a variable or a value has been discussed elsewhere (4721499), but that's in the weeds.) Here's a simple fix to ch.16, though I suspect there is a trap lurking somewhere: "An access to its value consists of the simple name of the variable***, or its simple name qualified by this,*** occurring anywhere in an expression except as..."
08-12-2010