Java:静态初始化

Java: Static initialization

你能解释一下两者之间的区别吗:

public class Test {

    public static final Person p;

    static {
        p = new Person();
        p.setName("Josh");
    }

}

public class Test {

    public static final Person p = initPerson();

    private static Person initPerson() {
        Person p = new Person();
        p.setName("Josh");
        return p;
    }

}

我一直使用第二种,但是与静态初始化块有什么区别吗?

initPerson 需要在某个时候调用,而静态块在创建 Test 对象时执行。

每次调用都会执行一个静态方法(第二个例子)。静态初始化块(第一个示例)仅在初始化 class.

时调用一次

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

The advantage of private static methods is that they can be reused later if you need to reinitialize the class variable.

这不算 final 个实例,因为 final 变量只能初始化一次。

当然存在技术差异(如果你愿意,你可以在你的 class 中多次调用静态方法,你可以通过反射等调用它)但是,假设你不做任何那个诡计,你是对的——这两种方法实际上是相同的。

我也更喜欢基于方法的方法,因为它给代码块起了一个好听的名字。但这几乎完全是一种文体方法。

正如 Marko 指出的那样,基于方法的方法还用于分离创建 Person 并将其分配给静态变量这两个问题。对于静态块,这两件事结合在一起,如果块不平凡,这会损害可读性。但是对于方法方法,方法负责创建对象,而静态变量的初始化负责获取该方法的结果和将其分配给变量。

更进一步:如果我有两个静态字段,并且一个依赖于另一个,那么我将声明两个方法,并让第二个方法将第一个变量作为显式参数。我喜欢让我的静态初始化方法 完全 没有状态,这使得更容易推断出应该在什么时候发生(以及它假定已经创建了哪些变量)。

所以,类似于:

public class Test {
    public static final Person p = initPerson();
    public static final String pAddress = lookupAddress(p);

    /* implementations of initPerson and lookupAddress omitted */
}

很明显,(a) 您不需要 pAddress 来初始化 p,并且 (b) 您 需要 需要p 来初始化lookupAddress。事实上,如果您以相反的顺序尝试它们并且您的静态字段不是 final:

,编译器会给您一个编译错误 ("illegal forward reference")
public static String pAddress = lookupAddress(p); // ERROR
public static Person p = initPerson();

你会失去静态块的清晰度和安全性。这编译得很好:

static {
    pAddress = p.findAddressSomehow();
    p = new Person();
}

...但它会在 运行 时失败,因为在 p.findAddressSomehow() 时,p 的默认值为 null

函数前的静态指定您可以通过在 Class 名称句柄本身上调用它来使用该函数。例如,如果你想在 class 之外创建一个 Person 对象,你可以写

Person p = Test.initPerson(); 

但是,两者之间没有优势区别,因为在这两种情况下都可以访问 class 之外的对象 p。