Когда метод add() добавляет объект в коллекцию
У меня есть два вопроса. Во-первых, рассмотрите приведенный ниже код.
public class Test{
private static final List<String> var = new ArrayList<String>() {{
add("A");
add("B");
System.out.println("INNER : " + var);
}};
public static void main(String... args){
System.out.println("OUTER : " + var);
}
}
Когда я запускаю этот код, он дает мне результат ниже
INNER : null
OUTER : [A, B]
Может ли кто-нибудь объяснить, почему INNER
является нулевым и исполняемым потоком в то время, когда именно "A" и "B" добавляются в collection
?
Во-вторых, я внес некоторые изменения в код выше и изменил его ниже одного (просто добавьте метод добавления в первую скобку)
public class Test{
private static final List<String> var = new ArrayList<String>() {
public boolean add(String e) {
add("A");
add("B");
System.out.println("INNER : " + var); return true;
};
};
public static void main(String... args){
System.out.println("OUTER : "+var);
}
}
После запуска выше кода я получил результат ниже
OUTER : []
После этого я совершенно не знаю, что происходит. Куда пошел INNER
? Почему это не печатает? Не называется ли это?
Ответы
Ответ 1
-
Поскольку блок инициализатора анонимного класса с ArrayList
выполняется до того, как ссылка на экземпляр анонимного класса будет присвоена var
.
-
Код не выполняется, потому что вы никогда не вызываете метод add(String e)
. Если вы это сделали, это приведет к StackOverflowError
, так как add("A")
является рекурсивным вызовом.
Ответ 2
-
Созданный объект не был назначен var
в процедуре инициализации, попробуйте следующее:
private static final List<String> var = new ArrayList<String>() {{
add("A");
add("B");
System.out.println("THIS : " + this); // THIS : [A, B]
System.out.println("INNER : " + var); // INNER : null
}};
-
Вы просто переопределите метод add
ArrayList
, он был вызван. Он работает так:
static class CustomList<E> extends ArrayList<E> {
@Override
public boolean add(String e) {
add("A");
add("B");
System.out.println("INNER : " + var);
return true;
}
}
private static final List<String> var = new CustomList<>();
Ответ 3
В фрагменте кода 1 вы используете инициализацию двойной привязки для добавления элементов в список массивов. Это в основном анонимный внутренний класс с инициализатором экземпляра. Поскольку вы печатаете var
до того, как объект был создан, он равен null
.
Во втором фрагменте вы создаете анонимный класс ArrayList, обеспечивающий реализацию метода add
. Но никто не вызывает метод add
в объекте ArrayList.
EDIT: Хорошая точка, сделанная Andreas @. Даже если вы вызовете метод add, это приведет к бесконечному рекурсивному вызову, что приведет к StackOverflowError
.
Ссылка:
Инициализация массива в одной строке
Ответ 4
В первом коде вы печатаете переменную до того, как ее конструктор вернется при добавлении элементов и распечатает список внутри инициализатора экземпляра. Поэтому он может печатать только null
.
Во втором коде вы переопределяете add()
для добавления жестко заданных элементов, но add()
никогда не вызывается в созданном экземпляре. Поэтому add()
не печатает ничего, и ничего не добавляется в экземпляр List.
Чтобы добавить элементы в список, вы обычно хотите вызвать add()
в ссылке List, например:
List<String> list = new ArrayList<>();
list.add("element A");
list.add("element B");
Для такого требования вы не создаете анонимный класс.
Если вы хотите использовать более простой синтаксис, который вы все еще можете сделать:
List<String> list = new ArrayList<>(Arrays.asList("element A", "element B"));