Java:静态初始化

Héc*_*tor 5 java static

你能解释一下我之间的区别是什么:

public class Test {

    public static final Person p;

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

}
Run Code Online (Sandbox Code Playgroud)

public class Test {

    public static final Person p = initPerson();

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

}
Run Code Online (Sandbox Code Playgroud)

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

ysh*_*vit 7

当然有技术差异(你可以在你的课程中多次调用静态方法,你可以通过反射调用它等)但是,假设你没有做任何这样的诡计,你是对的 - 这两种方法实际上完全相同.

我也更喜欢基于方法的方法,因为它为代码块提供了一个很好的名称.但它几乎完全是一种风格方法.

正如Marko所指出的那样,基于方法的方法还用于分离创建Person的两个问题,并将其分配给静态变量.使用静态块,这两个东西被组合在一起,如果块是非平凡的,则会损害可读性.但该方法的方法,该方法负责单独创建对象,和静态变量的initializion负责仅仅采取这种方法的结果,并将其分配给变量.

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

所以,像:

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

    /* implementations of initPerson and lookupAddress omitted */
}
Run Code Online (Sandbox Code Playgroud)

这是从看说的很清楚,即(一)你不需要pAddress初始化p,以及(b)你需要p进行初始化lookupAddress.实际上,如果您以相反的顺序尝试它们并且您的静态字段是非编译器,编译器会给您一个编译错误("非法转发引用")final:

public static String pAddress = lookupAddress(p); // ERROR
public static Person p = initPerson();
Run Code Online (Sandbox Code Playgroud)

使用静态块会丢失清晰度和安全性.编译得很好:

static {
    pAddress = p.findAddressSomehow();
    p = new Person();
}
Run Code Online (Sandbox Code Playgroud)

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