I made a class that contains:
static final
variablestatic
initializer block with a System.out.println()
statementIf I call the static final
variable from another class, the static
block does not execute.
As far as I know, the static
initializer block executes when the class is loaded in memory.
In this case, what is happening at the memory level?
Is the class not loading in memory? If not, where do other classes get the address of the final static
variable?
Case 1: static
block does NOT execute
class Test2 {
static final int a = 20;
static {
System.out.println("one");
}
}
Case 2: static
block does execute
class Test2 {
static final int a;
static {
a = 20;
System.out.println("one");
}
}
Output
class Test {
public static void main(String[] args) {
System.out.println(Test2.a);
}
}
Case 1:
20
Case 2:
one
20
So what is happening at both levels?
Yes of course: static final variables can be initialized in a static block but.... you have implicit GOTOs in that example ( try/catch is essentially a 'GOTO catch if something bad happens'). If an exception is thrown your final variables will not be initialized.
A developer needs to combine the keywords static final to achieve this in Java. The static keyword means the value is the same for every instance of the class. The final keyword means once the variable is assigned a value it can never be changed.
Static blocks can be used to initialize static variables or to call a static method. However, an instance block is executed every time an instance of the class is created, and it can be used to initialize the instance data members.
Static methods can only access the static members of the class and can only be called by other static methods. Final class can't be inherited by any class. The static class object can't be created and it only contains static members only. Final keyword doesn't support any block for initialization of final variables.
My guess is that your field is of either a primitive type or String
, and is initialized with a compile-time constant expression.
For static final fields initialized with a constant expression (and only such fields) - any code which refers to the field will have the constant value baked into it, rather than going via the static field which would cause class initialization. The "constant expression" part is important though. We can see this with a small test app:
class Fields {
public static final String CONSTANT = "Constant";
public static final String NON_CONSTANT = new String("Non-constant");
static {
System.out.println("Initializing");
}
}
public class Test {
public static void main(String arg[]) {
System.out.println(Fields.CONSTANT);
System.out.println(Fields.NON_CONSTANT);
}
}
The output is:
Constant
Initializing
Non-constant
Accessing the constant field does not require initialization, but accessing the non-constant one does. Using a non-final field would have the same effect: it would no longer count as a constant, basically.
The information about "this is a constant" gets baked into the class declaring a field. For example, using javap -c Fields
we see the two fields:
public static final java.lang.String CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String Constant
public static final java.lang.String NON_CONSTANT;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Note the ConstantValue
part of the CONSTANT
field metadata, which is missing from the NON_CONSTANT
field metadata.
See section 15.28 of the JLS for more on what constitutes a constant expression.
Section 12.4.1 of the JLS specifies when a class is initialized:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
(Emphasis mine.)
A static final field is a compile-time constant and its value is hardcoded into the destination class without a reference to its origin;
therefore your main class does not trigger the loading of the class containing the field;
therefore the static initializer in that class is not executed.
See the magic removing final
from definition. You will see static initialiser executing
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With