зачем использовать две большие фигурные скобки в нижнем коде? здесь это не анонимный внутренний класс) [duplicate]

Вы не можете явно передать что-либо в файл String, который не является String. Вы должны использовать либо:

"" + myInt;

, либо:

Integer.toString(myInt);

или:

String.valueOf(myInt);

Я предпочитаю вторую форму, но я думаю, что это личное

Изменить ОК, вот почему я предпочитаю вторую форму. Первая форма, скомпилированная, может создавать экземпляр StringBuffer (в Java 1.4) или StringBuilder в 1.5; еще одна вещь - собирать мусор. Насколько я могу судить, компилятор не оптимизирует это. Вторая форма также имеет аналог Integer.toString(myInt, radix), который позволяет указать, хотите ли вы шестнадцатеричный, восьмеричный и т. Д. Если вы хотите быть последовательным в своем коде (чисто эстетически, я думаю), вторая форма может использоваться в большем количестве мест.

Редактировать 2 Я предположил, что вы имели в виду, что ваше целое число было int, а не Integer. Если это уже Integer, просто используйте toString() на нем и сделайте это.

219
задан Andrew Tobilko 1 June 2016 в 10:48
поделиться

12 ответов

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

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

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

205
ответ дан Brian Agnew 17 August 2018 в 08:42
поделиться
  • 1
    Спасибо за разъяснение смысла внутренней и внешней фигурных скобок. Я задавался вопросом, почему внезапно появляются две фигурные скобки с особым смыслом, когда они на самом деле являются нормальными конструкциями java, которые появляются только как волшебный новый трюк. Такие вещи заставляют меня задавать синтаксис Java. Если вы уже не специалист, это может быть очень сложно читать и писать. – jackthehipster 9 July 2014 в 12:53
  • 2
    & quot; Магический синтаксис & quot; как это существует на многих языках, например, почти все C-подобные языки поддерживают «0», синтаксис «x - & gt; 0 & Quot; для петель, который является просто «x-- & gt; 0 & Quot; с необычным размещением пространства. – Joachim Sauer 5 January 2018 в 13:03
  • 3
    Мы можем просто заключить, что «инициализация с двойной привязкой» не существует сам по себе, это всего лишь комбинация создания анонимного класса и блока инициализации , который после объединения выглядит выглядит как синтаксическая конструкция, но на самом деле это не так. – MC Emperor 5 January 2018 в 14:55

Для забавного применения инициализации двойной скобки см. здесь Массив Dwemthy's в 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 и & hellip; короткое бекон!

21
ответ дан akuhn 17 August 2018 в 08:42
поделиться

Я думаю, что важно подчеркнуть, что в Java нет такой вещи, как «Инициализация двойного браслеза». Веб-сайт Oracle не имеет этого термина. В этом примере используются две функции: анонимный класс и блок инициализатора. Похоже, что старый блок инициализатора был забыт разработчиками и вызвал некоторую путаницу в этой теме. Цитирование из Oracle docs :

Блоки инициализатора для переменных экземпляра выглядят так же, как и статические блоки инициализатора, но без статического ключевого слова:

{
    // whatever code is needed for initialization goes here
}
9
ответ дан Alex T 17 August 2018 в 08:42
поделиться

Чтобы избежать всех отрицательных эффектов инициализации двойной комбинации, например:

  1. Сломанная «равна» совместимости.
  2. При выполнении прямых назначений никаких проверок не выполнялось.
  3. Возможные утечки памяти.

делать следующие вещи:

  1. Сделать отдельный класс «Builder» особенно для инициализации двойной привязки.
  2. Объявить поля со значениями по умолчанию.
  3. Поместить метод создания объекта в этот класс.

Пример:

public class MyClass {
    public static class Builder {
        public int    first  = -1        ;
        public double second = Double.NaN;
        public String third  = null      ;

        public MyClass create() {
            return new MyClass(first, second, third);
        }
    }

    protected final int    first ;
    protected final double second;
    protected final String third ;

    protected MyClass(
        int    first ,
        double second,
        String third
    ) {
        this.first = first ;
        this.second= second;
        this.third = third ;
    }

    public int    first () { return first ; }
    public double second() { return second; }
    public String third () { return third ; }
}

Использование :

MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();

Преимущества:

  1. Просто использовать.
  2. Не разрывает совместимость «равно».
  3. Вы может выполнять проверки в методе создания.
  4. Отсутствует утечка памяти.

Недостатки:

  • Нет.

И, как результат, у нас самый простой шаблон java-строителя.

См. все образцы в github: java-sf-builder-simple-example

4
ответ дан Boris Podchezertsev 17 August 2018 в 08:42
поделиться

Это будет выглядеть так же, как и ключевое слово с таким популярным в flash и vbscript. Это метод изменения того, что this есть, и не более того.

0
ответ дан Chuck Vose 17 August 2018 в 08:42
поделиться
  • 1
    На самом деле, нет. Это было бы похоже на то, что создание нового класса - это метод изменения того, что this. Синтаксис просто создает анонимный класс (поэтому любая ссылка на this будет ссылаться на объект этого нового анонимного класса), а затем использует инициализационный блок {...} для инициализации вновь созданного экземпляра. – grinch 19 June 2013 в 21:58

Вы можете поместить некоторые инструкции Java в цикл для инициализации коллекции:

List<Character> characters = new ArrayList<Character>() {
    {
        for (char c = 'A'; c <= 'E'; c++) add(c);
    }
};

Random rnd = new Random();

List<Integer> integers = new ArrayList<Integer>() {
    {
         while (size() < 10) add(rnd.nextInt(1_000_000));
    }
};

Но этот случай влияет на производительность, проверьте это обсуждение

3
ответ дан Community 17 August 2018 в 08:42
поделиться

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

Во-вторых, почти все ответы говорят о том, что это используется при создании анонимных внутренних классов. Я думаю, что люди, читающие эти ответы, получат впечатление, что это используется только при создании анонимных внутренних классов. Но он используется во всех классах. Чтение этих ответов - это какое-то новое особое будущее, посвященное анонимным классам, и я думаю, что это вводит в заблуждение.

. Идем дальше, этот вопрос говорит о ситуации, когда вторая открывающая скобка находится сразу после первого открытия скобки. Обычно в обычном классе есть некоторый код между двумя фигурными скобками, но это абсолютно одно и то же. Так что это вопрос размещения скобок. Поэтому я думаю, что мы не должны говорить, что это какая-то новая захватывающая вещь, потому что это то, что мы все знаем, но просто написано с некоторым кодом между скобками. Мы не должны создавать новую концепцию, называемую «инициализация двойной скобки».

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

Кроме того, мы не должны говорить о проблеме, созданной используя эту несуществующую вещь «инициализацию двойной скобки» или даже обычную инициализацию одной скобки, поскольку описанные проблемы существуют только из-за создания анонимного класса, поэтому он не имеет ничего общего с исходным вопросом. Но все ответы дают читателям впечатление, что это не вина в создании анонимных классов, а эта злая (несуществующая) вещь, называемая «инициализация двойной скобки».

7
ответ дан ctomek 17 August 2018 в 08:42
поделиться

вы имеете в виду что-то вроде этого?

List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}};

это инициализация списка массивов во время создания (hack)

3
ответ дан dhblah 17 August 2018 в 08:42
поделиться

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

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

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. Вероятно, вы не хотите рисковать этим:

Memory Leak Right Here [/g5]

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

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

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

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

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

212
ответ дан Lukas Eder 17 August 2018 в 08:42
поделиться
  • 1
    «Вы создаете слишком много анонимных классов». - глядя на то, как (скажем) Scala создает анонимные классы, я не уверен, что это проблема major – Brian Agnew 26 January 2016 в 13:07
  • 2
    @BrianAgnew: Это зависит от контекста, конечно. – Lukas Eder 26 January 2016 в 13:30
  • 3
    Разве он не остается действительным и приятным способом объявления статических карт? Если HashMap инициализируется с помощью {{...}} и объявлен как поле static, не должно быть никакой возможной утечки памяти, только одного анонимного класса и без ссылок на экземпляр экземпляра, верно? – lorenzo-s 2 December 2016 в 11:05
  • 4
    @ lorenzo-s: Да, 2) и 3) тогда не применяются, только 1). К счастью, с Java 9, для этой цели, наконец, Map.of(), так что это будет лучшее решение – Lukas Eder 2 December 2016 в 14:30
  • 5
    Возможно, стоит отметить, что внутренние карты также имеют ссылки на внешние карты и, следовательно, косвенно на ReallyHeavyObject. Кроме того, анонимные внутренние классы захватывают все локальные переменные, используемые внутри тела класса, поэтому, если вы используете не только константы для инициализации коллекций или карт с помощью этого шаблона, то внутренние экземпляры классов будут захватывать все их и продолжать ссылаться на них, даже когда они фактически удаляются из коллекции или карты. Таким образом, в этом случае эти экземпляры требуют не только дублирования памяти, но и утечки памяти в этом отношении. – Holger 12 July 2018 в 15:30

Он - среди других применений - ярлык для инициализации коллекций. Подробнее ...

3
ответ дан miku 17 August 2018 в 08:42
поделиться
  • 1
    Ну, это одно приложение для него, но отнюдь не единственное. – skaffman 24 December 2009 в 16:12
  • Первая скобка создает новый анонимный внутренний класс.
  • Второй набор фигурных скобок создает инициализаторы экземпляра, такие как статический блок в классе.

Например:

   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, поэтому этот внутренний класс способен использовать метод add ().

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

more

35
ответ дан Premraj 17 August 2018 в 08:42
поделиться
0
ответ дан hamza belmellouki 29 October 2018 в 13:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: