Java ArrayList из ArrayList
Следующие выходы кода
[[100, 200, 300], [100, 200, 300]].
Однако, я ожидаю, что
[[100, 200, 300], [100, 200]],
Где я ошибаюсь?
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> inner = new ArrayList<Integer>();
inner.add(100);
inner.add(200);
outer.add(inner);
outer.add(inner);
outer.get(0).add(300);
System.out.println(outer);
}
Ответы
Ответ 1
Вы добавляете ссылку на тот же внутренний ArrayList
дважды во внешний список. Поэтому, когда вы меняете внутренний список (добавив 300), вы видите его в "обоих" внутренних списках (когда на самом деле есть только один внутренний список, для которого две ссылки хранятся во внешнем списке).
Чтобы получить желаемый результат, вы должны создать новый внутренний список:
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> inner = new ArrayList<Integer>();
inner.add(100);
inner.add(200);
outer.add(inner); // add first list
inner = new ArrayList<Integer>(inner); // create a new inner list that has the same content as
// the original inner list
outer.add(inner); // add second list
outer.get(0).add(300); // changes only the first inner list
System.out.println(outer);
}
Ответ 2
Это то, что у вас есть сейчас
ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> inner = new ArrayList<Integer>();
создаст
outer -> []
inner -> []
После
inner.add(100);
inner.add(200);
ваша ситуация выглядит как
outer -> []
inner -> [100, 200]
Здесь возникает запутанная часть
outer.add(inner);
outer.add(inner);
который фактически копирует значение ссылки inner
, что означает, что они указывают на тот же список из inner
outer -> [ reference1 , reference2 ]
| |
+-------+ |
+---------------------+
↓
inner +-> [100, 200]
что означает, что если вы измените состояние списка, удерживаемого inner
, вы сможете увидеть эти изменения, используя reference1
и reference2
. То же самое, если вы измените этот список с помощью других ссылок, поэтому, когда вы используете
outer.get(0).add(300);
get(0)
возвращает список, к которому вы можете получить доступ также через inner
или get(1)
и добавив новый элемент, поэтому теперь ситуация выглядит как
outer -> [ reference1 , reference2 ]
| |
+-------+ |
+---------------------+
↓
inner -> [100, 200, 300]
Вот почему, когда вы печатаете outer
, вы видите
[[100, 200, 300], [100, 200, 300]].
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
from get(0) from get(1)
На самом деле вам нужно создать отдельный список, поэтому reference1
и reference2
будут указывать на два отдельных списка. Поэтому вам нужно что-то вроде
outer -> []
inner1 -> [100, 200]
inner2 -> [100, 200]
который позже будет организован для
outer -> [ reference1 , reference2 ]
| |
+------+ |
↓ |
inner1 -> [100, 200] |
|
+--------------------+
↓
inner2 -> [100, 200]
Вы можете сделать это таким образом
List<List<Integer>> outer = new ArrayList<List<Integer>>();
List<Integer> inner1 = new ArrayList<Integer>();
List<Integer> inner2 = new ArrayList<Integer>();
inner1.add(100);
inner1.add(200);
inner2.add(100);
inner2.add(200);
outer.add(inner1);
outer.add(inner2);
outer.get(0).add(300);
System.out.println(outer);
Ответ 3
Команда outer.add(inner)
добавляет ссылку на inner
, а не ее копию.
Итак, когда вы добавляете две ссылки на inner
в ArrayList outer
, вы добавляете две одинаковые вещи. Изменение inner
через outer.get(0)
также изменяет значение в outer.get(1)
, потому что они относятся к одной и той же вещи.
Если вы создаете копию inner
и вместо этого используете это, вы будете иметь два разных экземпляра и сможете их модифицировать отдельно. Вы можете сделать это с помощью простой команды:
outer.add(new ArrayList<[var type]>(inner));
Инструкция для new ArrayList(inner)
создает новый ArrayList
с содержимым inner
внутри него - но не использует тот же экземпляр, что и inner
. Таким образом, вы сохраните контент, но не сохраните дублируемую ссылку.
Добавив новую копию вместо ссылки, вы можете изменить копию, не изменяя, что вы можете назвать "оригиналом".