Когда метод 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

  1. Поскольку блок инициализатора анонимного класса с ArrayList выполняется до того, как ссылка на экземпляр анонимного класса будет присвоена var.

  2. Код не выполняется, потому что вы никогда не вызываете метод add(String e). Если вы это сделали, это приведет к StackOverflowError, так как add("A") является рекурсивным вызовом.

Ответ 2

  1. Созданный объект не был назначен 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
    }};
    
  2. Вы просто переопределите метод 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"));