23

For example, consider code snap below:

public static final int a;
public static final int b;

static {
    a = 8;       // it's working
    Test.b = 10; // compilation error Test.b cannot be assigned. 
}

Why can't we use Test.b = 10; inside a static block of the Test class itself? Without the class name it's working fine.

Is there any reason behind this?

Thiago Negri
  • 5,221
  • 2
  • 28
  • 39
Snehal Patel
  • 1,282
  • 2
  • 11
  • 25
  • 3
    Because your class is not yet initialized when you are in a static initializer? Also probably because the JLS forbids it... – fge Dec 16 '14 at 13:45
  • 2
    Are you interested in "which bit of the JLS prohibits this" or "why was the language designed this way"? – Jon Skeet Dec 16 '14 at 13:46
  • Could be wrong here, but perhaps its because you have `Test.b` declared as `final` – JSK NS Dec 16 '14 at 13:48
  • @JSKNS it is true that removing the `final` modifier makes the error go away, but the question is why. – chiastic-security Dec 16 '14 at 13:52
  • because you can't modify final variables after they've been initialized. – JSK NS Dec 16 '14 at 13:53
  • 1
    @JSKNS: Where do you see it being initialized at the moment, other than that assignment? And how do you see that changing if you remove the `Test.` part? – Jon Skeet Dec 16 '14 at 13:54
  • The error goes away if you remove the `final` modifier, and the error I get from the compiler (Java 8) is `cannot assign a value to final variable y`, so the `final` is certainly significant. – chiastic-security Dec 16 '14 at 13:56
  • 1
    Are you looking for a secret Winter Bash hat for accumulating deleted answers on a question...? – chiastic-security Dec 16 '14 at 13:59

1 Answers1

10

A static final variable must be initialized before use. It may be initialized either directly at declaration time, or in a static block.

But when you use class.var = x it is not seen as an initialization but as an assignation.

With a JDK 7, the error is cannot assign a value to final variable.

That explains why it works if you remove the final keyword

class Test {

    static final int a = 2; // initialization at declaration time
    static final int b;
    static final int c;

    static {
        b = 4;  // initialization in static block
        Test.c = 6; // error : cannot assign a value to final variable c
    }
    ...

}

EDIT

In the JLS the correct word for initialization is definite assignement

Extract from the JLS :

For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.

Similarly, every blank final variable must be assigned at most once; it must be definitely unassigned when an assignment to it occurs.

Such an assignment is defined to occur if and only if either the simple name of the variable (or, for a field, its simple name qualified by this) occurs on the left hand side of an assignment operator.

For every assignment to a blank final variable, the variable must be definitely unassigned before the assignment, or a compile-time error occurs.

emphasize mine, but I think this is the real reason for the error.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 1
    I don't think this is quite right, though it must be along the right lines. This says that you can't assign to a blank final variable unless it's definitely unassigned at that point, but it is definitely unassigned. It doesn't seem to me to violate the bit you quote. – chiastic-security Dec 16 '14 at 14:20
  • @chiastic-security : I'm not really a lawyer, and english is not my first language, by I think that the important word here is *simple name* because `Test.b` is not a simple name. – Serge Ballesta Dec 16 '14 at 14:24
  • Yes, that phrase is important, but all it says is that `Test.b = 10` isn't "such an assignment", i.e., this code isn't in view for this bit of the JLS. – chiastic-security Dec 16 '14 at 14:26
  • @chiastic-security : You are right. I forgot the first line of the paragraph that states *For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.*. Added. – Serge Ballesta Dec 16 '14 at 14:31
  • I read that, but I'm not convinced it helps. The code doesn't *access* the field at all; it only assigns to it. (As far as I can see, *access* implies a read operation.) – chiastic-security Dec 16 '14 at 14:36
  • 1
    @chiastic-security : As I said english is not my first language and I thought *access* could be a write as well as a read what would be coherent with the text of the error. – Serge Ballesta Dec 16 '14 at 14:38
  • It's really hard to pinpoint in the JLS. You could argue that, since final fields can only be assigned once, and an assignment through something that's not a simple name doesn't cause definite assignment, and definite assignment is required at the end of the static block; then assignment not through a simple name must be forbidden because it precludes correct definite assignment. – Erwin Bolwidt Dec 16 '14 at 14:39