静态块和具有静态非原始数据字段的Field.get(null)

时间:2011-11-14 17:49:46

标签: java reflection static

我有以下课程:

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);
    }

}

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();
            }
        }
    }

}

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 + "]";
    }

}

执行A时,我得到:

B.load -> field is null
B.load -> field is null
C [key=key1, value=value1]

为什么field.get(null)在执行时会返回空值?我没有例外,似乎Javadoc没有解释这种行为。

2 个答案:

答案 0 :(得分:1)

我相信所有静态成员都将按声明顺序执行(对于静态块)并初始化(对于静态字段)。尝试将类A的静态块放在类的末尾,或者至少在静态字段之后。 Lemme知道这是否有所作为。

编辑:关于基元和字符串的行为的信息......

当你有一个最终静态字段是一个原语或一个字符串文字(或一个可以静态评估导致其中一个的表达式)时,它被认为是一个编译时常量。基本上,设置这样的值不需要“计算”,例如调用构造函数或评估可能尚未初始化的其他字段。尽管字符串不是原语,但它们在编译时会得到特殊的处理,以使代码中的字符串文字成为可能。

这意味着只要加载了一个类并准备初始化就可以分配这些字段。虽然我不知道关于这一点的规范细节,但试验反射表明这是必须发生的事情。

以下Java语言规范部分与理解此行为相关:

答案 1 :(得分:1)

在A类中,您必须在调用静态函数之前声明静态字段

public static final C field1 = new C("key1", "value1");

public static final C field2 = new C("key2", "value2");

static {
    B.load(A.class);
}

Java tutorial解释了它:

A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code.