инициализация статического поля ArrayList с использованием анонимного класса, включая инициализатор блока - PullRequest
0 голосов
/ 28 июня 2018

Я играл в javaDeathmatch и столкнулся с вопросом, на который я не смог ответить. Вы можете мне помочь?

public class DeathMatch {
    private static final List<String> NAMES = new ArrayList<>() {{
        add("John");
        System.out.println(NAMES);
    }};

    public static void main(String[] args) {
        //Nothing in particular
    }
}

В этом случае, когда мы запускаем JVM, класс будет загружен, и в первую очередь его статический член 'NAMES' будет создан и инициализирован. ArrayList также инициализируется через анонимный класс, включая инициализатор блока. Но проблема в том, что мы добавляем «John» к этой ссылке и печатаем NAMES, и, таким образом, он показывает ноль. Код будет работать правильно, если мы сделаем изменения следующим образом:

System.out.println(this);

вместо:

System.out.println(NAMES);

Почему это так?

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

Причина, по которой инициализация для List NAMES еще не завершена, поэтому вы получаете null для NAMES, но получаете [John] при использовании ключевого слова this, если вы печатаете это в main, он будет производить желаемый результат.

0 голосов
/ 28 июня 2018

Когда вы используете инициализацию «двойные скобки», вы создаете анонимный подкласс ArrayList с внешними скобками, а внутренняя пара скобок представляет инициализатор экземпляра, где вы вызываете add и распечатываете NAMES. Но в тот момент, когда вы создаете ArrayList, ArrayList еще не закончил построение, и он еще не был назначен на NAMES. Переменная NAMES по-прежнему имеет значение по умолчанию null.

Несмотря на то, что синтаксис может выглядеть красиво, обычно не стоит создавать анонимный подкласс просто ради простой инициализации на глаз.

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

private static final List<String> NAMES = new ArrayList<String>();
static {
    NAMES.add("John");
    System.out.println(NAMES);
}
0 голосов
/ 28 июня 2018
new ArrayList<>() {{
    add("John");
    System.out.println(NAMES);
}};

По существу можно рассматривать как

new MyList();

, где MyList определяется как:

class MyList extends ArrayList<String> {
    public MyList() {
        super();
        add("John");
        System.out.println(NAMES);
    }
}

Порядок событий идет:

  1. Позвонить конструктору
  2. Назначить объект, возвращаемый конструктором, в статическое поле с именем 'NAMES'

Так как System.out.println происходит в конструкторе , вызов его с помощью NAMES означает, что присвоение еще не произошло и не работает, но вызов его с помощью this допустим.


Вы должны предпочесть одно из следующего (в зависимости от версии Java и количества элементов):

private static final List<String> NAMES = Arrays.asList("John");
private static final List<String> NAMES = List.of("John");
private static final List<String> NAMES = Collections.singletonList("John");

с последующим статическим блоком для печати:

static {
    System.out.println(NAMES);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...