-1

I am new to Java and trying to wrap my head around the difference between defining a variable as static, and including a variable within a static block. I have formulated a simplified example to illustrate my confusion:

import java.util.Properties;

public class Foo {
    static Properties myProps = new Properties();

    static {
        Properties myOtherProps = new Properties();
    }
    
    public static void bar()  {
        Foo.myProps.forEach(myProps::put); // Works just fine
        Foo.myOtherProps.forEach(myProps::put); // Throws cannot find symbol error
    }
}

The static variable myProps seems to be referenced normally by the bar() method while myOtherProps can't be referenced from that part of the code.

What is the difference here between wrapping code in a static code block vs. defining a variable as static?

alt-f4
  • 2,112
  • 17
  • 49
  • If I am being downvoted, can I at least understand why? – alt-f4 Jul 18 '20 at 05:12
  • 1
    The `static {}` block is not a mechanism for declaring multiple static fields without having to explicitly type "static" for each one. It is a "static initializer" which is executed when the class itself is initialized (which happens some time after it's loaded but before its first use). You can put arbitrary code in an initializer block, but that code is scoped to said block. The compilation error you get is no different than if you declared a variable inside a method and then tried to access it in some other method. – Slaw Jul 18 '20 at 06:13

2 Answers2

2

myProps is a class variable, and pretty much always exists, and can be referenced as Foo.myProps, or just myProps within the scope of class Foo.

myOtherProps is a local variable, and only exists from the point of declaration until the end of the block containing the declaration. It can only be addressed as myOtherProps, and only without the scope of the static block.

Background Information

As stated in the Java Language Specification, section 4.12.3. Kinds of Variables, there are 8 kinds of variables. The code in the question uses 2 of them:

  1. A class variable is a field declared using the keyword static within a class declaration (§8.3.1.1), or with or without the keyword static within an interface declaration (§9.3).

    A class variable is created when its class or interface is prepared (§12.3.2) and is initialized to a default value (§4.12.5). The class variable effectively ceases to exist when its class or interface is unloaded (§12.7).

...

  1. Local variables are declared by local variable declaration statements (§14.4).

    Whenever the flow of control enters a block (§14.2) or for statement (§14.14), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block or for statement.

    A local variable declaration statement may contain an expression which initializes the variable. The local variable with an initializing expression is not initialized, however, until the local variable declaration statement that declares it is executed. (The rules of definite assignment (§16 (Definite Assignment)) prevent the value of a local variable from being used before it has been initialized or otherwise assigned a value.) The local variable effectively ceases to exist when the execution of the block or for statement is complete.

Andreas
  • 154,647
  • 11
  • 152
  • 247
1

That's because variables exist and accessible only in their scope (and child scope).

In this case you define myOtherProps in a sibling scope to bar's scope, so you can't access it.

The solution: is to define the variable in the class scope

The static block is used for static initializations of a class. If you want a lot of things to happen in a static context, what you should do is to define the variables in a parent scope, then access them in a child scope:

Properties myOtherProps;

static {
    myOtherProps = new Properties();
}

public static void bar()  {
    Foo.myOtherProps.forEach(myProps::put); // will work
}
    
Omri Attiya
  • 3,917
  • 3
  • 19
  • 35