Java Синтаксический сахар

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

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

Ответ 1

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

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

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

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

Основное место, которое эти инициализаторы полезны, как это при создании экземпляров карт, то есть:

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

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

Ответ 2

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

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

Ответ 3

Это инициализатор экземпляра (не статический инициализатор).

Рассмотрим определение класса

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, - это трюк, чтобы оживить внешний вид конструкции замыкания.

Ответ 4

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

Трюк состоит в том, чтобы представить, что "новый Expectation()" заменен на "класс Something extends Expectation".

Ответ 5

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

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

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

чтобы инициализировать содержимое коллекции.

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

Ответ 6

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

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

Ответ 7

Первичной мотивацией этого, я считаю, является создание нового пространства имен, в котором имена, определенные в 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);
    ...
}