14

我今天碰到了这段代码,不知道它是如何工作的。我知道如何创建匿名类,但我习惯于看到方法签名而不仅仅是一对大括号。这些大括号之间的代码是否放入静态块中?它进入构造函数吗?还是完全是别的东西?

conext.checking(new Expectations() {
    { // <- what does this pair of braces do?
        oneOf(alarm).getAttackAlarm(null);
    }
});
4

7 回答 7

18

它是一个实例初始化程序,在创建的对象的上下文中调用代码。

这相当于

Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)

编写它的人可能认为他通过不声明变量(不正确)或者它是更简洁的代码(我不同意)来提高效率。

这些初始化器像这样有用的主要地方是实例化映射时,即:

Map map = new HashMap() {{
  put("key1", "value1");   
  put("key2", "value2"); 
}};

我认为实际上更具可读性。

于 2010-10-05T18:57:48.960 回答
4

它是一个初始化块,但不一定是静态初始化块。它实际上是匿名内部类的构造函数。您通常会看到这种“双大括号初始化”模式来方便地创建和填充集合:

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
});
于 2010-10-05T19:00:08.057 回答
3

它是一个实例初始化器(不是静态初始化器)。

考虑类的定义

public class Foo {
    private int i = getDefaultValue();

    private static int getDefaultValue() {
        return 5;
    }
}

getDefaultValue()对initalises的调用i本质上是一个代码块,每次构造 Foo 的实例时都会运行该代码块。该符号扩展了该功能以允许更复杂的初始化。例如

public class Foo {
    private int i;

    {
        int z = 4 + 5;
        i = z + getDefaultValue();
    }

    private static int getDefaultValue() {
        return 5;
    }
}

在 JMock 中使用它的方式是一种让期望看起来像闭包构造的技巧。

于 2010-10-05T19:02:44.203 回答
1

发生了什么 ?外部大括号创建一个从 Exception 派生的新匿名类。内大括号定义一个初始化器并设置oneOf()等。

为什么要这样做?这是构造和初始化类实例的单行技巧。e. 你有时会看到这样的东西:

new HashSet<String>(){{ add("one"); add("two"); }}

初始化集合的内容。

缺点?因为您在包含类中创建了一个匿名类,所以该匿名类隐含地包含对外部类的 this 引用。通常不是问题,但如果(例如)您想要序列化您这样构建的类,它可能会导致问题。

于 2010-10-05T18:59:18.847 回答
0

这是一个初始化程序块。如果不查看其余代码,我无法说出它的作用。

诀窍是想象将“new Expectation()”替换为“class Something extends Expectation”。

于 2010-10-05T18:53:41.573 回答
0

Anynoymous 内部类没有构造函数,因此您可以像这样定义实例初始化器,即内部大括号集是实例初始化器。

new Expectations() { 
    { 
        oneOf(alarm).getAttackAlarm(null); 
    }
}
于 2010-10-05T19:04:44.360 回答
0

我相信,这背后的主要动机是创建一个新的名称空间,在其中定义的名称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);
    ...
}
于 2010-10-05T20:25:50.477 回答