Что это за вызов конструктора со следующими двойными скобками? - PullRequest
15 голосов
/ 08 июля 2009

К сожалению, я не кодирую Java около пяти лет, и я совершенно не могу вспомнить, как или почему работает следующий код.

Я наткнулся на похожий пример и разбил его на это. Акцент сделан на части под комментарием: я не получаю обозначение конструктора, за которым следует блок в двойных скобках. И, к сожалению, я не могу найти что-либо в документации Java или с помощью Google (какое слово (а) я должен Google?).

package syntaxtest;

public class Main {

    public static void main(String[] args) {

        // What kind of notation is this?
        MyTest tester = new MyTest() {{
            setName("John Johnson");
        }};

        System.out.println(tester.getName());
    }
}


class MyTest {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Итак, вот мои вопросы:

  1. Как называется эта запись / синтаксис?
  2. Где я могу прочитать об этом документацию?

Полагаю / надеюсь, что смогу ответить на второй вопрос самостоятельно, если кто-нибудь сможет дать мне ответ на первый вопрос.

Чтобы было понятно: я знаю, что вывод John Johnson;) Но я не знаю, почему он работает.

Ответы [ 3 ]

21 голосов
/ 08 июля 2009

Это известно как инициализация двойной скобки :

Первая фигурная скобка создает новую AnonymousInnerClass, второй объявляет блок инициализатора экземпляра который запускается, когда анонимный внутренний класс создан. Этот тип Блок инициализатора формально называется «инициализатор экземпляра», потому что это объявляется в рамках экземпляра класса - «статические инициализаторы» являются связанной концепцией, где ключевое слово static ставится перед скобка, которая начинает блок, и которая выполняется на уровне класса, как только как загрузчик классов завершает загрузку класс (указан в http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6) Блок инициализатора может использовать любой методы, поля и конечные переменные доступный в содержании, но нужно быть осторожным с тем фактом, что инициализаторы запускаются раньше Конструкторы.

Это работает только для не финала классы, потому что это создает Анонимный подкласс.

15 голосов
/ 08 июля 2009

Давайте раскроем код немного по-другому:

MyTest tester = new MyTest() {
  {
    setName("John Johnson");
  }
};

То, что вы видите здесь, называется инициализация двойной скобкой . У вас есть анонимный внутренний подкласс класса MyTest вместе с блоком инициализатора, который представляет собой блок, содержащий код, который запускается при создании объекта.

Обычно вы бы помещали такой код в конструктор, но поскольку анонимные внутренние классы не могут иметь конструкторов, это единственный способ гарантировать выполнение кода, когда он должен.

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

final Map<String, Integer> textToInt = Collections.unmodifiableMap(new HashMap<String, Integer>() {{
    put("one", 1);
    put("two", 2);
    // etc
}});

, которая создает новую карту, переопределяет ее, добавляет к ней некоторые значения в блоке инициализатора и переносит ее в неизменяемую карту.

0 голосов
/ 09 июля 2009
MyTest tester = new MyTest() {{
   setName("John Johnson");
}};

совпадает с

MyTest tester = new MyTest();
tester.setName("John Johnson");
...