0
public class TestStatic{
  static {a=2;}
  static int a=1;
  static int b=3;
  static {b=4;}
  public static void main(String[] args){
    System.out.println(a);
    System.out.println(b);}
  }
}

the output is

1
4

I wonder why the a=2 doesn't throw an error, for a is not declared yet.

I understand the initialization order and static block "static {a=2;}" initializes before static variable "static int a=1;", just can't figure out the "a=2" part.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • I thought java variable should be declared before assignment. Sorry for being a beginner. I'd appreciate it if you can tell me where i can read the quotes. – bruce66623 Apr 27 '23 at 06:12
  • 2
    "I thought java variable should be declared before assignment" - that's only the case for *local* variables. – Jon Skeet Apr 27 '23 at 06:13
  • @JonSkeet maybe he thinks the static initialize block is executed before the static variables are created, rather than their location in the code – Stultuske Apr 27 '23 at 06:14
  • https://stackoverflow.com/questions/19561332/in-what-order-do-static-blocks-and-initialization-blocks-execute-when-using-inhe this answer will help – StevenLasagna Apr 27 '23 at 07:52

4 Answers4

3

A local variable can't be used earlier (lexicographically) than its declaration.

That's specified in JLS section 6.3

The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block, starting with the declaration's own initializer and including any further declarators to the right in the local variable declaration statement.

But that doesn't apply to fields, whether they're static or instance fields. Fields are members, and as it also says in section 6.3:

The scope of a declaration of a member m declared in or inherited by a class or interface C (§8.2, §9.2) is the entire body of C, including any nested class or interface declarations. If C is a record class, then the scope of m additionally includes the header of the record declaration of C.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

You can see what the scope of any declaration is, by reading section 6.3 of the Java Language Specification.

In particular,

The scope of a declaration of a member m declared in or inherited by a class or interface C is the entire body of C, including any nested class or interface declarations.

So the scope of a is the entire body of testStatic. The static initialiser is in the body of testStatic, so a is in scope in the body of the static initialiser.

No additional restrictions regarding whether a is accessible, or whether you can set it applies here, so a = 2; compiles.

In a sense, this works for the same reason that calling a method before it is declared works:

void f() {
    g(); // can call g here!
}

void g() {}

Note that this is different in the case of referring to other static fields in the field initialiser of a static field. i.e. this does not compile:

class Foo {
    static int b = a; // changing this to Foo.a works
    static int a = 0;
}

Even though a is in scope in the field initialiser of b, this is now allowed in the specification, section 8.3.3:

For a reference by simple name to a class variable f declared in class or interface C, it is a compile-time error if:

  • The reference appears either in a class variable initializer of C or in a static initializer of C (§8.7); and

  • The reference appears either in the initializer of f's own declarator or at a point to the left of f's declarator; and

  • The reference is not on the left hand side of an assignment expression (§15.26); and

  • The innermost class or interface enclosing the reference is C.

Also note that the scope of local variables does not include the code before it is declared:

The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block, starting with the declaration's own initializer and including any further declarators to the right in the local variable declaration statement.

Note the wording of "the rest of the block".

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • thanks for your detailed explaination! it helps me a lot. Now i understand my misunderstanding. I should read Java Language Specification carefully first. – bruce66623 Apr 27 '23 at 06:40
0

When in a static block, if a variable has not been declared or initialized, it's gonna be initialized to the default value of it's data type.

Here you are initializing an int ( a = 2 ), therefore it's first being initialized as an int with the value 0, and then the value 2 is stored inside.

As for why that works that way, well that's just how the language works

  • While it is true that a static variable is default-initialized, this is not relevant for this question. It is only possible to access/reference the variable in blocks that are lexically after the declaration. In the given example, it is not possible to observe the `0`. – Hulk Apr 27 '23 at 07:20
-1

The code you provided does not throw any errors because it correctly initializes the static variable x before it is used in the static block.

technically possible to initialize a variable in a static block before it is declared, it can make the code harder to understand and maintain. It's generally recommended to declare and initialize variables in the order they will be used, and to avoid using static blocks unless they are absolutely necessary.

  • this is imprecise at best: "because it correctly initializes the static variable x before it is used in the static block." - There is no static variable x in the code in the question, and no static variable is used in a static block (unless you mean the use in `main()`. – Hulk Apr 27 '23 at 07:28
  • @Hulk Sorry i don't follow why "static int a=1" is not a static variable and "static {a=2}"is not a static block? I thought it's the way that they should be declared. – bruce66623 Apr 28 '23 at 01:50
  • @bruce66623 there are static variables `a` and `b` in your example, but no `x`. Also, the static blocks only contain assignments, but never access (use) the initialized values. The reason why your code does compile is the scope of the fields, but it has nothing to do with whether the fields are initialized before the blocks. – Hulk Apr 28 '23 at 06:10
  • @Hulk Now i get it, thanks for answering! – bruce66623 Apr 28 '23 at 08:26