Вопрос-ответ

What is Double Brace initialization in Java?

Что такое инициализация двойными фигурными скобками в Java?

Что такое синтаксис инициализации двойными фигурными скобками ({{ ... }}) в Java?

Переведено автоматически
Ответ 1

Инициализация двойными фигурными скобками создает анонимный класс, производный от указанного класса (внешние фигурные скобки), и предоставляет блок инициализатора внутри этого класса (внутренние фигурные скобки). например

new ArrayList<Integer>() {{
add(1);
add(2);
}};

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

Ответ 2

Каждый раз, когда кто-то использует инициализацию двойными фигурными скобками, погибает котенок.

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

1. Вы создаете слишком много анонимных классов

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

Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};

... создаст эти классы:

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class

Это довольно большие накладные расходы для вашего загрузчика классов - впустую! Конечно, это не займет много времени на инициализацию, если вы сделаете это один раз. Но если вы сделаете это 20 000 раз в своем корпоративном приложении... вся эта куча памяти только ради небольшого количества "синтаксического сахара"?

2. Вы потенциально создаете утечку памяти!

Если вы возьмете приведенный выше код и вернете эту карту из метода, вызывающие этот метод могут ничего не подозревая удерживать очень тяжелые ресурсы, которые не могут быть собраны в мусор. Рассмотрим следующий пример.:

public class ReallyHeavyObject {

// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;

// This method almost does nothing
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};

return source;
}
}

Возвращаемое значение Map теперь будет содержать ссылку на заключенный экземпляр ReallyHeavyObject. Вы, вероятно, не хотите рисковать этим:

Утечка памяти прямо здесь

Изображение из http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern /

3. Вы можете притвориться, что в Java есть литералы отображения

Чтобы ответить на ваш актуальный вопрос, люди использовали этот синтаксис, чтобы притвориться, что в Java есть что-то вроде литералов map , похожих на существующие литералы array:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

Некоторым людям это может показаться синтаксически стимулирующим.

Ответ 3

  • Первая фигурная скобка создает новый анонимный внутренний класс.

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

Например:

   public class TestHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>(){
{
put("1", "ONE");
}{
put("2", "TWO");
}{
put("3", "THREE");
}
};
Set<String> keySet = map.keySet();
for (String string : keySet) {
System.out.println(string+" ->"+map.get(string));
}
}

}

Как это работает

Первая фигурная скобка создает новый анонимный внутренний класс. Эти внутренние классы способны получать доступ к поведению своего родительского класса. Итак, в нашем случае мы фактически создаем подкласс класса HashSet, поэтому этот внутренний класс способен использовать метод put() .

И Второй набор фигурных скобок - это не что иное, как инициализаторы экземпляра. Если вы помните основные концепции Java, то вы можете легко связать блоки инициализатора экземпляра со статическими инициализаторами благодаря схожей структуре, подобной фигурным скобкам. Единственное отличие заключается в том, что статический инициализатор добавляется с помощью ключевого слова static и запускается только один раз; независимо от того, сколько объектов вы создаете.

Еще

Ответ 4

Интересное применение инициализации двойными фигурными скобками смотрите Здесь Dwemthy's Array в Java .

Выдержка

private static class IndustrialRaverMonkey
extends Creature.Base {{
life = 46;
strength = 35;
charisma = 91;
weapon = 2;
}}

private static class DwarvenAngel
extends Creature.Base {{
life = 540;
strength = 6;
charisma = 144;
weapon = 50;
}}

А теперь будьте готовы к BattleOfGrottoOfSausageSmells и ... жирному бекону!

java