Java Syntactic Sugar
I ran into this block of code today, and I don't know how it works. I know how to make anonymous classes, but I'm us开发者_StackOverflow社区ed to seeing a method signature and not just a pair of braces. Is the code between those braces put into a static block? Does it go into the constructor? Or is it something else altogether?
conext.checking(new Expectations() {
{ // <- what does this pair of braces do?
oneOf(alarm).getAttackAlarm(null);
}
});
It's an instance initializer that calls the code within the context of the created object.
This is equivalent to
Expectations exp = new Expectations();
exp.oneOf(alarm).getAttackAlarm(null);
conext.checking(exp)
Whoever wrote it might have thought he was being more efficient by not declaring a variable (not true) or that it was cleaner code (I disagree).
The primary place that these initializers are useful like this is when instantiating maps, ie:
Map map = new HashMap() {{
put("key1", "value1");
put("key2", "value2");
}};
which I think actually is slightly more readable.
It is an initializer block, but not necessarily a static initializer block. It is effectively a constructor for an anonymous inner class. You will typically see this "double-brace initialization" pattern to conveniently create and populate collections:
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
});
It's an instance initialiser (not a static initialiser).
Consider the definition of a class
public class Foo {
private int i = getDefaultValue();
private static int getDefaultValue() {
return 5;
}
}
The call to getDefaultValue()
that initalises i
is essentially a code block that runs each time an instance of Foo is constructed. The notation extends that function to allow more complex initialisation. E.g.
public class Foo {
private int i;
{
int z = 4 + 5;
i = z + getDefaultValue();
}
private static int getDefaultValue() {
return 5;
}
}
The manner with which it is used in JMock is a trick to give expectations the look of a closure construct.
What's happening ? The outer braces create a new anonymous class derived from Exception. The inner braces define an initialiser and sets the oneOf()
etc.
Why do this ? It's a one-liner trick for constructing and initialising an instance of a class. e. you sometimes see something like this:
new HashSet<String>(){{ add("one"); add("two"); }}
to initialise the contents of a collection.
Downsides ? Because you're creating an anonymous class within the containing class, that anonymous class contains a this reference to the outer class implicitly. Not normally a problem, but it can cause issues if (say) you want to serialise a class that you've constructed like this.
It's an initializer block. I can't tell what it does without looking at the rest of the code.
The trick is to imagine "new Expectation()" replaced with "class Something extends Expectation".
Anynoymous inner classes don't have a constructor, so you can define a an instance initilizer like this i.e. the inner set of braces are the instance initializers.
new Expectations() {
{
oneOf(alarm).getAttackAlarm(null);
}
}
The primary motivation behind this, I believe, is to create a new name space, in which names defined in Expection
can be referenced more easily.
For example, suppose java.lang.Math
is not final,
new Math()
{{
double x = sin(23.65);
double y = log(x);
...
}};
It's almost as if we have something like
with names from Math
{
double x = sin(23.65);
double y = log(x);
...
}
精彩评论