为什么使用静态块直接初始化实例变量?
为什么我要使用静态块:
static { B = 10; }
过度:
Integer B = 10;
一个优于另一个的优点/缺点是什么?
只在必要时才应使用静态初始化程序块。 例如,有时您需要执行几个步骤来计算字段的最终值。 在这种情况下,您有两个机会:编写一个计算值的方法并将您的字段声明为static final Integer B = calculateB()
,或使用初始化块:
static final Integer B; static { int temp = ...; ... B = temp; }
在这种情况下,我更喜欢静态块,因为方法可能会令人困惑(其他开发人员可能会尝试调用它,尽管它只是在初始化期间被调用一次)。
这同样适用于实例字段,尽管通常可以避免exception的初始化块,只需将字段的初始化逻辑写入构造函数(当然静态字段不可能)。
static
块允许您为属性编写更复杂的初始化逻辑,而单行初始化将您限制为单个表达式。
请注意,实例和静态属性都存在初始化块,例如,这个初始化块在实例化时初始化实例属性:
private int a; { a = 10; }
而这个在类加载时初始化静态属性:
private static int b; static { b = 10; }
这里详细解释了初始化过程,作为JVM规范的一部分。
加载类时会发生静态初始化。
例如,它是一个初始化成员变量的适当位置,否则由于多个线程的访问而需要同步。
如果你明确地调用构造函数,第二种情况就会发生。
用法不同。
例如,你更喜欢第二种情况下延迟加载某些东西(如果你把它放在静态初始化器中它总是加载,也许你不想要那个 – 更喜欢延迟加载它)
首先, Integer B
看起来是一个非静态成员变量,无法从静态块访问。 所以你要么写作
//Initialize static field static { B = 10; } static Integer B = 10;
要么
//Initialize member field { B = 10; } Integer B = 10;
在这两种情况下,您都可以使用它来初始化B,其值可能会导致exception或执行更复杂的操作而无需为init编写特殊方法。
{ try{ B = thisWillThrowAFileNotFound(); }catch(FileNotFoundException){ B = 10;//Set default } }
实际上,如果你有
private static Integer B = 10;
编译器将转换为,基本上:
private static Integer B; static { B = 10; }
静态块的东西是你可以使用整个语言而不仅仅是表达式来进行初始化。 想象一下,你需要一个具有7的倍数的数组。你可以这样做:
private static Integer[] array; static { array = new Integer[1000]; for (int i = 0; i < 1000; i++) { array[i] = 7 * i; } }
无论如何,你也可以这样做:
private static Integer[] array = initArray(); private static Integer[] initArray() { Integer[] result = new Integer[1000]; for (int i = 0; i < 1000; i++) { result[i] = 7 * i; } return result; }