Подтвердить что ты не робот

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);

}
4b9b3361

Ответ 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. Таким образом, вы сохраните контент, но не сохраните дублируемую ссылку.

Добавив новую копию вместо ссылки, вы можете изменить копию, не изменяя, что вы можете назвать "оригиналом".