Java ArrayList ArrayList

Następujący kod wyjścia

[[100, 200, 300], [100, 200, 300]]. 

Jednak oczekuję

[[100, 200, 300], [100, 200]], 
Gdzie się mylę?
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);

}
Author: Martin G, 2014-08-06

3 answers

Dodajesz odwołanie do tego samego wewnętrznego ArrayList dwa razy do zewnętrznej listy. Dlatego, gdy zmieniasz wewnętrzną listę (dodając 300), widzisz ją w " obu " wewnętrznych listach (gdy w rzeczywistości jest tylko jedna wewnętrzna lista, dla której dwa odwołania są przechowywane na zewnętrznej liście).

Aby uzyskać pożądany rezultat, należy utworzyć nową wewnętrzną listę:

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);
}
 34
Author: Eran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-05 20:48:14

This is what you have now

ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> inner = new ArrayList<Integer>();        

Utworzy

outer -> []
inner -> []

Po

inner.add(100);     
inner.add(200);

Twoja sytuacja wygląda jak

outer -> []
inner -> [100, 200]

Here comes confusing part

outer.add(inner);
outer.add(inner);

Które w rzeczywistości kopiują wartość inner referencji, co oznacza, że wskazują na tę samą listę z inner

outer -> [ reference1 , reference2 ]
              |             |
      +-------+             |
      +---------------------+
      ↓
inner +-> [100, 200]

Co oznacza, że jeśli zmienisz stan listy posiadanej przez inner będziesz mógł zobaczyć te zmiany używając reference1 i reference2. To samo, jeśli zmienisz tę listę za pomocą innych referencje, więc kiedy używasz

outer.get(0).add(300);

get(0) zwraca listę, do której można uzyskać dostęp również za pomocą inner lub get(1) i dodając nowy element tak, aby sytuacja wyglądała następująco

outer -> [ reference1 , reference2 ]
              |             |
      +-------+             |
      +---------------------+
      ↓
inner -> [100, 200, 300]

Dlatego kiedy drukujesz outer widzisz

[[100, 200, 300], [100, 200, 300]]. 
 ^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^
   from get(0)      from get(1)

To, czego potrzebujesz, to utworzyć osobną listę, aby reference1 i reference2 wskazywały na dwie oddzielne listy. Więc potrzebujesz czegoś takiego jak

outer  -> []
inner1 -> [100, 200]
inner2 -> [100, 200]

Które zostaną później zorganizowane do

outer -> [ reference1 , reference2 ]
              |             |
       +------+             |
       ↓                    |
inner1 -> [100, 200]        |
                            |
       +--------------------+
       ↓
inner2 -> [100, 200]

You can do it this sposób

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);
 34
Author: Pshemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-11 16:15:12

Polecenie outer.add(inner) dodaje odniesienie do inner, a nie jego kopię.

Więc, kiedy dodajesz dwa odniesienia do inner do ArrayList outer, dodajesz dwa z tego samego. Modyfikowanie inner przez outer.get(0) również modyfikuje wartość w outer.get(1), ponieważ odnoszą się one do tej samej rzeczy.

Jeśli utworzysz kopię inner i użyjesz jej zamiast, będziesz miał dwie różne instancje i będziesz mógł je modyfikować oddzielnie. Można to zrobić za pomocą prostego polecenia:

outer.add(new ArrayList<[var type]>(inner));

The instrukcja dla new ArrayList(inner) tworzy nowy ArrayList z zawartością inner wewnątrz - ale nie używa tej samej instancji co inner. W ten sposób zachowasz zawartość, ale nie zachowasz zduplikowanego odniesienia.

Dodając nową kopię zamiast referencji, możesz zmodyfikować kopię bez modyfikowania tego, co możesz nazwać " oryginałem."

 9
Author: Zyerah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-05 20:34:40