简体   繁体   English

Java:静态初始化

[英]Java: Static initialization

can you explain me which is the difference between: 你能解释一下我之间的区别是什么:

public class Test {

    public static final Person p;

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

}

and

public class Test {

    public static final Person p = initPerson();

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

}

I have always used the second one, but is there any difference with an static initializer block? 我一直使用第二个,但静态初始化块有什么区别吗?

There are of course technical differences (you could invoke the static method multiple times within your class if you wanted, you could invoke it via reflection, etc) but, assuming you don't do any of that trickery, you're right -- the two approaches are effectively identical. 当然有技术差异(你可以在你的课程中多次调用静态方法,你可以通过反射来调用它等)但是,假设你没有做任何这种诡计,你是对的 - 这两种方法实际上完全相同。

I also prefer the method-based approach, since it gives a nice name to the block of code. 我也更喜欢基于方法的方法,因为它为代码块提供了一个很好的名称。 But it's almost entirely a stylistic approach. 但它几乎完全是一种风格方法。

As Marko points out, the method-based approach also serves to separate the two concerns of creating the Person, and assigning it to the static variable. 正如Marko所指出的那样,基于方法的方法还用于分离创建Person的两个问题,并将其分配给静态变量。 With the static block, those two things are combined, which can hurt readability if the block is non-trivial. 使用静态块,这两个东西被组合在一起,如果块是非平凡的,则会损害可读性。 But with the method approach, the method is responsible solely for creating the object, and the static variable's initializion is responsible solely for taking that method's result and assigning it to the variable. 但该方法的方法,该方法是专门负责创建对象,和静态变量的initializion是专门负责采取这一方法的结果并将其分配给变量。

Taking this a bit further: if I have two static fields, and one depends on the other, then I'll declare two methods, and have the second method take the first variable as an explicit argument. 更进一步:如果我有两个静态字段,一个依赖于另一个,那么我将声明两个方法,并让第二个方法将第一个变量作为显式参数。 I like to keep my static initialization methods entirely free of state, which makes it much easier to reason about which one should happen when (and what variables it assumes have already been created). 我喜欢保持我的静态初始化方法完全没有状态,这使得更容易推断出应该发生哪一个(以及它假定已经创建了哪些变量)。

So, something like: 所以,像:

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

    /* implementations of initPerson and lookupAddress omitted */
}

It's very clear from looking at that, that (a) you don't need pAddress to initialize p , and (b) you do need p to initialize lookupAddress . 这是从看说的很清楚,即(一)你不需要pAddress初始化p ,和(b) 需要p初始化lookupAddress In fact, the compiler would give you a compilation error ("illegal forward reference") if you tried them in reverse order and your static fields were non- final : 实际上,如果您以相反的顺序尝试它们并且您的静态字段是非final ,编译器会给您一个编译错误(“非法转发引用”):

public static String pAddress = lookupAddress(p); // ERROR
public static Person p = initPerson();

You would lose that clarity and safety with static blocks. 使用静态块会丢失清晰度和安全性。 This compiles just fine: 编译得很好:

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

... but it'll fail at run time, since at p.findAddressSomehow() , p has its default value of null . ...但它在运行时会失败,因为在p.findAddressSomehow()p的默认值为null

A static method (second example) is executed every time you call it. 每次调用时都会执行静态方法(第二个示例)。 A static init block (first example) is only called once on initializing the class. 静态初始化块(第一个示例)仅在初始化类时调用一次。

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html 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. 私有静态方法的优点是,如果需要重新初始化类变量,它们可以在以后重用。

This does not count for final instances, because a final variable can only be initialized once. 这不计入final实例,因为最终变量只能初始化一次。

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

The static before a function specifies that you can use that function by calling it on the Class name handle itself. 函数之前的静态指定您可以通过在类名称句柄本身上调用它来使用该函数。 For example, if you want to create a Person object outside the class you can write 例如,如果要在类之外创建一个Person对象,则可以编写

Person p = Test.initPerson(); 

However, there is no advantageous difference between the two as you can access the object p outside the class in both cases. 但是,两者之间没有明显的区别,因为在这两种情况下都可以访问类外的对象p。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM