可能重复:
实例初始化器与构造器有何不同?
当所有需要的工作都可以在构造函数中完成时,为什么我们还需要 Java 中的非静态块呢?
编辑:非静态块每次在构造函数之前运行的普通类怎么样?
除了@Bohemian 的回答。
如果您有多个构造函数,则初始化程序块避免重复。
public class A {
final Map<String, String> map = new HashMap<String, String>(); {
// put things in map.
}
final int number; {
int number;
try {
number = throwsAnException();
} catch (Exception e) {
number = 5;
}
this.number = number;
}
public A() { /* constructor 1 */ }
public A(int i) { /* constructor 2 */ }
}
每次在构造函数之前运行非静态块的普通类怎么样?
从技术上讲,顺序是
实际上,所有这些代码都在每个构造函数的字节码中,因此在运行时构造函数之前或之后没有任何内容。
在对初始化顺序有任何混淆之前
public class Main extends SuperClass {
{
System.out.println("Initialiser block before constructor");
}
Main() {
System.out.println("Main constructor");
}
{
System.out.println("Initialiser block after constructor");
}
public static void main(String... args) {
new Main() {{
System.out.println("Anonymous initalizer block");
}};
}
}
class SuperClass {
SuperClass() {
System.out.println("SuperClass constructor");
}
}
印刷
SuperClass constructor
Initialiser block before constructor
Initialiser block after constructor
Main constructor
Anonymous initalizer block
您可以将它与匿名类一起使用:
new MyClass() {
{
// do something extra on construction (after the constructor executes)
}
}
我发现这对于初始化“查找”地图(即固定内容)特别有用:
Map<String, String> map = new HashMap<String, String>() {
{
put("foo", "bar");
put("one", "two");
// etc
}
};
仅供参考,这有时(不好)称为“双括号初始化”,而实际上它只是使用初始化块。
尽管这样一个匿名类在技术上是一个子类,但在将使用这种技术与更传统的技术来创建不可修改的地图进行比较时,它的美妙之处就显现出来了:
比较这个简单的单行,它将数据和分配放在一起:
private static final Map<String, String> map = Collections.unmodifiableMap(
new HashMap<String, String>() {{
put("foo", "bar");
put("one", "two");
// etc
}});
由于final
只允许一个分配,因此必须创建一个单独的对象:
private static final Map<String, String> map;
static {
Map<String, String> tempMap = new HashMap<String, String>();
tempMap.put("foo", "bar");
tempMap.put("one", "two");
// etc
map = Collections.unmodifiableMap(tempMap);
}
另请注意,在混乱版本中,两个语句不必相邻,因此不可修改映射的内容可能变得不那么明显。