Java语法糖
我今天遇到了这段代码,我不知道它是如何工作的。我知道如何创建匿名类,但我习惯于看到方法签名,而不仅仅是一对大括号。这些大括号之间的代码是否放在静态块中?它进入构造函数了吗?还是完全是另外一回事Java语法糖,java,syntactic-sugar,Java,Syntactic Sugar,我今天遇到了这段代码,我不知道它是如何工作的。我知道如何创建匿名类,但我习惯于看到方法签名,而不仅仅是一对大括号。这些大括号之间的代码是否放在静态块中?它进入构造函数了吗?还是完全是另外一回事 conext.checking(new Expectations() { { // <- what does this pair of braces do? oneOf(alarm).getAttackAlarm(null); } }); conext.checki
conext.checking(new Expectations() {
{ // <- what does this pair of braces do?
oneOf(alarm).getAttackAlarm(null);
}
});
conext.checking(新期望值(){
{/这是一个初始化程序块。如果不看代码的其余部分,我就无法判断它的作用
技巧是将“new Expectation()”替换为“class Something extensed Expectation”。它是一个实例初始值设定项,在所创建对象的上下文中调用代码
这相当于
Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)
不管是谁写的,他都可能认为不声明变量(不是真的)或者代码更简洁(我不同意)
这些初始值设定项的主要用途是在实例化映射时,即:
Map map = new HashMap() {{
put("key1", "value1");
put("key2", "value2");
}};
我认为这实际上更具可读性。发生了什么事?外部大括号创建了一个从Exception派生的新匿名类。内部大括号定义了一个初始化器,并设置了oneOf()
等
为什么要这样做?这是构造和初始化类实例的一个单行程序技巧。例如,您有时会看到这样的情况:
new HashSet<String>(){{ add("one"); add("two"); }}
newhashset(){{{add(“一”);add(“两”);}
初始化集合的内容
缺点?因为您正在包含类中创建一个匿名类,所以该匿名类隐式地包含了对外部类的引用。这通常不是问题,但是如果(比如)您希望序列化这样构造的类。它是一个初始值设定项块,但不一定是一个静态的初始值设定项块。它实际上是匿名内部类的构造函数。您通常会看到这种“双括号初始化”模式,以便方便地创建和填充集合:
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
});
private final Collection FIXED\u Collection=Collections.unmodifiableCollection(新HashSet())
{//第一组大括号声明匿名内部类
{add(1);add(2);add(3);}//第二个集合是初始值设定项块
});
它是一个实例初始化器(不是静态初始化器)
考虑类的定义
public class Foo {
private int i = getDefaultValue();
private static int getDefaultValue() {
return 5;
}
}
对初始化i
的getDefaultValue()
的调用本质上是一个代码块,每次构造Foo实例时都会运行该代码块。符号扩展了该函数以允许更复杂的初始化
public class Foo {
private int i;
{
int z = 4 + 5;
i = z + getDefaultValue();
}
private static int getDefaultValue() {
return 5;
}
}
在JMock中使用它的方式是一种给期望一个闭包构造的外观的技巧。任何一个重要的内部类都没有构造函数,因此您可以像这样定义一个实例初始化器,即内部大括号集是实例初始化器
new Expectations() {
{
oneOf(alarm).getAttackAlarm(null);
}
}
我认为,这背后的主要动机是创建一个新的名称空间,在这个空间中,Expection
中定义的名称可以更容易地被引用
例如,假设java.lang.Math
不是final
new Math()
{{
double x = sin(23.65);
double y = log(x);
...
}};
就好像我们有了
with names from Math
{
double x = sin(23.65);
double y = log(x);
...
}
它被称为“实例初始值设定项”,而不是“静态初始值设定项”(由于明显的原因,后者不会有this
)初始化器。该块将在每次运行代码时运行,而不是像静态初始化器那样第一次运行。我相信,这个特定的示例是推荐的(由他们的文档提供的)在JMock2中实现这一点的方法。尝试让用它编写的测试代码读起来相当自然。可读,是的。但我发现这样做绝对令人讨厌(不管怎样,在测试/脚本代码之外)。它创建了一个额外的类(和类文件)dty:不正确。我只是做了一个测试类来验证这一点。构造函数在初始值设定项之前运行。静态初始值设定项在构造函数之前运行,但这不是静态初始值设定项。我必须说,在15年的Java编程中,我从来没有遇到过使用初始值设定项的情况像以前一样。这种语法并不局限于匿名类。虽然它的使用在普通类中是不必要的,而且容易混淆。+1表示注意匿名类之外的用法。我还喜欢对闭包的引用!:-)