除了 @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);
}
Runnable
时认为子类化 Thread
是不恰当的。滥用继承要小心;其中提到的一个例子是它如何破坏 equals
的常见实现。您应该考虑使用 collection factory method。 - obatakuCollections.unmodifiableMap(newHashMap<String, String>("foo", "bar", "one", "two", ...))
。除此之外,我认为你应该了解Liskov替换原则。 - obatakuMap<String, Integer>
(我已经这样做了)- Java不支持混合变长参数,因此类型定义会更加棘手。此外,您可以定义和调用方便的方法,所有这些方法都可以正常工作。另外,HashMap
是如此基本的实用程序类,以至于没有人(除了你似乎)关心它是否被“子类化”。我鼓励我的团队使用这种模式,并进行重构以将上述丑陋版本转换为它。所以 :P - BohemianMaps.<String, String>newHashMap
*。但是不管怎样,它可以返回一个 Map<String, String>
(尽管根据方法的约定,这样做可能没有什么意义)。我并不是要挑剔,但是在像那样非传统方式使用继承时,应该小心谨慎。 - obataku
this()
的方法来解决问题。问题是,如果您添加构造函数,则需要记住在之前和之后添加位。不需要这样做要简单得多。 - Peter Lawrey