Java:静态初始化
你能解释一下这两者的区别吗Java:静态初始化,java,static,Java,Static,你能解释一下这两者的区别吗 public class Test { public static final Person p; static { p = new Person(); p.setName("Josh"); } } 及 我一直使用第二个,但是与静态初始值设定项块有什么区别吗?initPerson需要在某个点调用,而静态块是在创建测试对象时执行的。每次调用它时都会执行静态方法(第二个示例)。静态init块(第一个示例)在初
public class Test {
public static final Person p;
static {
p = new Person();
p.setName("Josh");
}
}
及
我一直使用第二个,但是与静态初始值设定项块有什么区别吗?initPerson需要在某个点调用,而静态块是在创建测试对象时执行的。每次调用它时都会执行静态方法(第二个示例)。静态init块(第一个示例)在初始化类时只调用一次 私有静态方法的优点是,如果需要重新初始化类变量,可以在以后重用它们
这不适用于
final
实例,因为final变量只能初始化一次。当然存在技术上的差异(如果需要,可以在类中多次调用静态方法,也可以通过反射等方式调用),但是,假设您不做任何此类操作,你说得对,这两种方法实际上是相同的
我也更喜欢基于方法的方法,因为它给代码块起了一个很好的名字。但这几乎完全是一种文体方法
正如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)初始化p
不需要pAddress
,以及(b)初始化lookupAddress
确实需要p
。事实上,如果您以相反的顺序尝试,并且静态字段不是final,编译器会给您一个编译错误(“非法正向引用”):
public static String pAddress = lookupAddress(p); // ERROR
public static Person p = initPerson();
使用静态块时,您将失去清晰度和安全性。这就很好地编译了:
static {
pAddress = p.findAddressSomehow();
p = new Person();
}
。。。但是它在运行时会失败,因为在
p.findaddress()
,p
的默认值为null
,函数指定可以通过在类名句柄本身上调用该函数来使用该函数之前的static。例如,如果要在类之外创建Person对象,可以编写
Person p = Test.initPerson();
但是,这两种情况之间没有有利的区别,因为在这两种情况下都可以在类之外访问对象p 除了在这种情况下,静态方法是私有的(意味着只有这个类可以调用它),并且在类初始化时只调用一次。我看到了您的编辑,但在这种情况下,变量是
final
——因此无法重新初始化。好的,它是私有的。但它也会在每次调用它时执行。如果你忘记打电话,也可能是零时间。在这个示例中,它从未被调用,但我认为这是一个错误。是的,它将在每次调用它时执行——在OP的第二个示例中,在初始化类的过程中,在public static final Person p=initPerson()期间执行一次在OP的第一个示例中,static{…}
块将被调用一次,作为初始化类的一部分。静态块在初始化类时执行,而不是每次创建测试对象时执行。然后也会调用initPerson
方法,因为它用于初始化静态字段。所以总结一下,静态块和静态初始化部分只执行一次,这就是你的意思,对吧,不仅仅是块的名称,控制反转也很重要:方法只返回值,而init块将其推入变量。由于静态类型系统保证方法将返回值,这提高了可读性和正确性。init块可以进行赋值,也可以不进行赋值,并且init块和变量之间没有紧密的关联。显式数据流值上的附加点为+1,尤其是在类初始化代码中。
Person p = Test.initPerson();