I have the following classes:
public class A {
static {
B.load(A.class);
}
public static final C field1 = new C("key1", "value1");
public static final C field2 = new C("key2", "value2");
public static void main(String[] args) {
System.out.println(A.field1);
}
}
and
public class B {
public static void load(Class<?> clazz) {
for (Field field : clazz.getFields()) {
try {
System.out.println("B.load -> field is " + field.get(null));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
and
public class C {
private final String key;
private final String value;
public C(String key, String value) {
super();
this.key = key;
this.value = value;
}
public String getKey() {
return this.key;
}
public String getValue() {
return this.value;
}
@Override
public String toString() {
return "C [key=" + this.key + ", value=" + this.value + "]";
}
}
When A is executed I get:
B.load -> field is null
B.load -> field is null
C [key=key1, value=value1]
Why does field.get(null) return a null value when it is executed? I get no exception and it seems that this behavior is not explained by the Javadoc.
I believe all static members will be executed (for static blocks) and initialized (for static fields) in declaration order. Try placing the static block of class
Aat the end of the class, or at least after the static fields. Lemme know if that makes a difference.EDIT: info regarding the behaviour for primitives and Strings…
When you have a final static field that is a primitive or a String literal (or an expression that can be statically evaluated that results in one of these), it’s considered a compile-time constant. Basically, setting such a value does not require “computation”, like invoking a constructor or evaluating vis-a-vis other fields that may not have been initialized yet. Although Strings aren’t primitives, they’re given a special treatment in compilation to make String literals in code a possibility.
This means such fields can be assigned as soon as a class has been loaded and is ready for initialization. Although I don’t know the specification details regarding that, experimenting with reflection shows that this is what must be happening.
Following sections of the Java language specification are relevant to understanding this behaviour: