2010-10-05 1 views
10

Сегодня я столкнулся с этим блоком кода, и я не знаю, как он работает. Я знаю, как создавать анонимные классы, но я привык видеть подпись метода, а не только пару фигурных скобок. Является ли код между этими скобками помещен в статический блок? Он входит в конструктор? Или это совсем другое?Java Syntactic Sugar

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

ответ

15

Это инициализатор экземпляра, который вызывает код внутри контекста созданного объекта.

Это эквивалентно

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

Кто писал он мог бы подумать, что он является более эффективным, не объявляя переменную (не так) или что это был чистый код (я не согласен).

Основное место, что эти Инициализаторы полезны, как это когда инстанцируют карты, то есть:

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

, который я думаю, что на самом деле это немного более удобные для чтения.

+1

Это называется «экземпляр инициализатор», а не «статический инициализатор» (у последнего не было бы «этого» по понятным причинам). Также см. Http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 –

+1

Это не статический инициализатор, а просто (экземпляр) инициализатора. Этот блок будет запускаться * каждый раз *, этот код запускается не только в первый раз, как это происходит со статическим инициализатором. –

+0

Хорошо, я исправил это .... –

0

Это блок инициализатора. Я не могу сказать, что он делает, не глядя на остальную часть кода.

Трюк заключается в том, чтобы представить, что «новое ожидание() заменено на« класс «Что-то расширяет ожидание».

0

Что происходит? Внешние создают новый анонимный класс, полученный из Exception. Внутренние скобы определяют инициализатор и устанавливают oneOf() и т. Д.

Зачем это делать? Это однострочный трюк для построения и инициализации экземпляра класса. е. вы иногда видите примерно следующее:

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

для инициализации содержимого коллекции.

Недостатки? Поскольку вы создаете анонимный класс внутри содержащего класса, этот анонимный класс неявно ссылается на эту ссылку на внешний класс. Обычно это не проблема, но это может вызвать проблемы, если (скажем) вы хотите сериализовать класс, который вы создали таким образом.

+0

Не * статический * инициализатор. – DJClayworth

+0

Ах. Виноват. Исправлено –

3

Это блок инициализатора, но необязательно статический блок инициализатора. Он эффективно является конструктором для анонимного внутреннего класса. Вы обычно видите это «инициализация двойной фигурной скобки» шаблон для удобного создания и заполнения коллекции:

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 
}); 
+0

Я должен сказать, что через 15 лет программирования Java я никогда не сталкивался с используемым ранее инициализатором. – dty

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 трюк, чтобы дать ОЖИДАНИЯ вид закрывающей конструкции.

+0

+1 для обозначения использования вне анонимных классов. Мне также нравится ссылка на закрытие! :-) – dty

0

Внутренние классы Anynoymous не имеют конструктора, поэтому вы можете определить инициализатор экземпляра, подобный этому, т.е. внутренний набор фигурных скобок является инициализатором экземпляра.

new Expectations() { 
    { 
     oneOf(alarm).getAttackAlarm(null); 
    } 
} 
+1

Этот синтаксис не ограничивается анонимными классами. Хотя его использование не является необходимым и запутанным в обычном классе. – dty

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); 
    ... 
}