【发布时间】:2012-08-08 17:29:22
【问题描述】:
可能重复:
How is an instance initializer different from a constructor?
当所有需要的工作都可以在构造函数中完成时,为什么我们还需要 Java 中的非静态块呢?
编辑:非静态块每次在构造函数之前运行的普通类怎么样?
【问题讨论】:
标签: java
可能重复:
How is an instance initializer different from a constructor?
当所有需要的工作都可以在构造函数中完成时,为什么我们还需要 Java 中的非静态块呢?
编辑:非静态块每次在构造函数之前运行的普通类怎么样?
【问题讨论】:
标签: 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
【讨论】:
number的声明放在同一行看起来有点混乱。
this() 问题是如果添加构造函数,请记住在之前和之后添加位。不需要这样做要简单得多。
您可以将它与匿名类一起使用:
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
}
};
仅供参考,这有时(不太好)称为“双括号初始化”,而实际上它只是使用initializer block。
虽然这样一个匿名类在技术上是一个子类,但在将使用这种技术与创建unmodifiable 映射的更传统技术进行比较时,它的美妙之处就显现出来了:
比较这个简单的单行,它将数据和赋值放在一起:
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);
}
还要注意,在混乱版本中,两个语句不必相邻,因此不可修改映射的内容可能变得不那么明显。
【讨论】:
Runnable 时认为子类化Thread 是不恰当的。滥用继承权时要小心;提到的一个例子是它如何破坏equals 的常见实现。您可能应该考虑使用collection factory method。
Collections.unmodifiableMap(newHashMap<String, String>("foo", "bar", "one", "two", ...))。除此之外,我认为您应该查看Liskov Substitution Principle。
Maps.<String, String>newHashMap*。但无论如何,它可以返回一个Map<String, String>(尽管考虑到方法合同,这将毫无意义)。我并不是想成为一个书呆子,但在以这种非常规的方式使用继承时应该小心。