Инициализация двойной скобки Java работает всегда?
Я знаю, что этот код:
Set<String> set = new HashSet<String>() {{
add("test1");
add("test2");
}};
действительно:
Set<String> set = new HashSet<String>() {
{//initializer
add("test1");
add("test2");
}
};
Блок инициализатора выполняется перед блоком конструктора. В приведенном выше примере add("test1") вызывается перед выполнением конструктора. Конструктор может инициализировать многие поля экземпляра, чтобы этот класс работал. Мне интересно, почему вызов .add(), прежде чем конструктор будет работать? Есть ли случаи, которые вызывают проблему?
4 ответа
Есть деталь, которую вы оставили, которая объясняет это.
Прежде всего, давайте рассмотрим шаги с 3 по 5 процедуры инициализации (кратко):
3. конструктор суперкласса называется
4. инициализаторы экземпляра называются
5. тело конструктора называется
Деталь, которую вы упустили, заключается в том, что ваше выражение не просто создает новый экземпляр HashSet
класс, это на самом деле создает новый экземпляр анонимного подкласса HashSet
, (Я считаю, что это указано в разделе 15.9.1.)
Поскольку вы не объявляли конструктор, используется конструктор по умолчанию. Но до этого конструктор суперкласса HashSet
завершено.
Итак, в итоге, HashSet
Конструктор завершается до запуска вашего блока инициализатора.
Это предположение неверно:
Блок инициализатора выполняется перед блоком конструктора.
Потому что в данном конкретном случае блок инициализатора является частью блока конструктора.
В документах четко указано, что
Компилятор Java копирует блоки инициализатора в каждый конструктор. Следовательно, этот подход можно использовать для совместного использования блока кода между несколькими конструкторами.
Я думаю, что вы путаете со статическими инициализаторами.
Инициализаторы экземпляра выполняются сразу после создания объекта. Вы в основном создаете встроенное расширение HashSet, а затем "сразу после" его создания вы добавляете в него два элемента.
Это шаблон общего использования в фиктивных объектах для тестирования, например в JMock, но также имеет и другие полезные применения.
Надеюсь это поможет.
Я считаю, что это плохая практика, потому что это создает бессмысленные подклассы, которые могут повлиять на использование памяти и производительность приложения. В любом случае, программа верна, потому что конструктор суперкласса вызывается перед инициализаторами экземпляров. Поэтому, когда ваш инициализатор запущен, HashSet
конструктор запустил так вызов add
буду работать.