我今天遇到了这段代码,我不知道它是如何工作的。我知道如何制作匿名类,但我习惯于看到一个方法签名,而不仅仅是一对大括号。这些大括号之间的代码是否放入静态块?它会进入构造函数吗?还是完全不同的东西?
conext.checking(new Expectations() {
{ // <- what does this pair of braces do?
oneOf(alarm).getAttackAlarm(null);
}
});
它是一个实例初始值设定项,用于在创建的对象的上下文中调用代码。
这相当于
Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)
写这篇文章的人可能会认为他没有声明一个变量(不是真的)或者它是更干净的代码(我不同意)更有效率。
这些初始化程序像这样有用的主要位置是实例化地图,即:
Map map = new HashMap() {{
put("key1", "value1");
put("key2", "value2");
}};
我认为实际上更具可读性。
它是初始化块,但不一定是静态初始化块。它实际上是匿名内部类的构造函数。您通常会看到这种“双支撑初始化”模式,以方便地创建和填充集合:
private final Collection<Integer> FIXED_COLLECTION = Collections.unmodifiableCollection(new HashSet<Integer>()
{ // first set of braces declares anonymous inner class
{ add(1); add(2); add(3); } // second set is initializer block
});
它是一个实例初始化器(不是静态初始化器)。
考虑一个类的定义
public class Foo {
private int i = getDefaultValue();
private static int getDefaultValue() {
return 5;
}
}
调用getDefaultValue()
的i
实际上是一个代码块,每次构造一个Foo实例时都会运行。该表示法扩展了该功能以允许更复杂的初始化。例如。
public class Foo {
private int i;
{
int z = 4 + 5;
i = z + getDefaultValue();
}
private static int getDefaultValue() {
return 5;
}
}
它在JMock中的使用方式是一种让期望看起来像闭包构造的技巧。
发生了什么 ?外括号创建一个派生自Exception的新匿名类。内括号定义了初始化器并设置了oneOf()
等。
为什么这样?这是构建和初始化类实例的单线技巧。即你有时会看到这样的东西:
new Set<String>(){{add("one");add("two")}}
初始化集合的内容。
下行?因为您在包含类中创建了一个匿名类,所以该匿名类隐式包含对外部类的this引用。通常不是问题,但是如果你想要序列化你这样构建的类,它可能会导致问题。
这是一个初始化块。如果不查看其余代码,我无法分辨它的作用。
诀窍是想象“新的期望()”被“类别扩展期望”所取代。
Anynoymous内部类没有构造函数,因此您可以像这样定义一个实例initilizer,即内部大括号集是实例初始值设定项。
new Expectations() {
{
oneOf(alarm).getAttackAlarm(null);
}
}
我相信,这背后的主要动机是创建一个新的名称空间,其中可以更容易地引用Expection
中定义的名称。
例如,假设java.lang.Math
不是最终的,
new Math()
{{
double x = sin(23.65);
double y = log(x);
...
}};
这几乎就像我们有类似的东西
with names from Math
{
double x = sin(23.65);
double y = log(x);
...
}