2013-04-24 19 views
17
int[][] array = new int[][] {...} 
int[][] clone = array.clone(); 

Naiwnie oczekiwałem, że to zadziała. Ale tak się nie stało - sklonował tylko pierwszy wymiar i musiałem ręcznie sklonować inny wymiar, jeśli chciałem prawdziwego klona. Uwaga: zawartość została poprawnie skopiowana. Ale kiedy zmienił clone[0][1], to odzwierciedlenie w array[0][1]Klonowanie tablic wielowymiarowych

I choć .clone() wiadomo wykonać płytkie klon, int[][] wygląda pojedynczego obiektu (jeśli nie znamy jej wewnętrzny realizacji, co najmniej)

Dlaczego czy to zachowanie zostało wybrane? Czy nie odwołuje się do obiektu tablicy, a nie tylko do pierwszego wymiaru tablicy? A w jakich scenariuszach klonowanie tylko pierwszego wymiaru jest pożądanym zachowaniem?

Odpowiedz

8

Dlaczego to zachowanie zostało wybrane?

Spójność, najprawdopodobniej.

Jak można powiedzieć, int[][] odwołuje się do obiektu tablicy. Tak się składa, że ​​zawartość każdego elementu tablicy to inna tablica, ale to tylko szczegół. Java klonuje wszystkie tablice identycznie, a ponieważ elementy mogą być dowolnego typu, nie może zagwarantować wykonania głębokiej kopii.

Stąd clone() dla tablic wykonuje płytką kopię, więc tylko pierwszy wymiar jest klonowany.

(Generalnie nie wydaje się, że istnieje jedna "najlepsza" lub "oczywista" odpowiedź na pytanie, czy klon zawiera głębokie lub płytkie kopie. To, czego deweloper chce, zależy od tego, w jaki sposób każde pole jest używane przez aplikację, więc uniwersalne podejście będzie oczywiście miało ograniczenia.)

3

To zachowanie zostało zademonstrowane, ponieważ nie ma prawdziwej tablicy wielowymiarowej.

Java osiąga wiele wymiarów poprzez tworzenie tablic tablic. Co oznacza:

int[][] is actually Array<Array<int>> 

Z tego powodu klon skopiowałby tylko pierwszy wymiar.

Jeśli próbujesz z trójwymiarową tablicą, będziesz musiał trzykrotnie sklonować.

1

Metoda ta jest płytką kopią (patrz another stackoverflow answer on the clone method), co oznacza, że ​​wszystkie elementy są kopiowane przez odniesienie.

Aby dostać się do tego, co chcesz (zwane również głębokim klonowaniem), możesz albo skopiować każdą pojedynczą tablicę samodzielnie, używając rekurencyjnie Arrays.copy, więc każda znaleziona (pod) tablica dostanie głęboki klon, albo sprawdź this stackoverflow answer on deep cloning.

okazji włamania :-)

1

nie jestem faktycznie w stanie replikować zachowanie już wspomniałem. Widzę kilka odpowiedzi, w których płytka kopia jest główną przyczyną problemu. Popraw mnie, jeśli się mylę, płytka kopia oznacza po prostu, że zamiast kopiowania obiektu podczas klonowania otrzymamy kopię odniesienia.Dobre wyjaśnienie można znaleźć tutaj: In Java, what is a shallow copy?

W tym przypadku płytka kopia upewni się tylko, że zmiany w oryginalnej tablicy zostaną odzwierciedlone w klonowanej tablicy, ale nie powstrzymają niczego przed skopiowaniem.

int[][] array = new int[][] {{1,2,3},{4,5,6}, {7,8,9}}; 
int[][] clone = array.clone(); 

//Try this to see magic of shallow copy 
//array[2][1]=11; 

for(int i=0;i<array.length;i++) 
    for(int j=0;j<array[i].length;j++) 
     System.out.println("array["+i+"]["+j+"]"+array[i][j]); 

for(int i=0;i<clone.length;i++) 
    for(int j=0;j<clone[i].length;j++) 
     System.out.println("clone["+i+"]["+j+"]"+clone[i][j]); 

Klonowanie odbywa się idealnie, ponieważ obie tablice mają tę samą zawartość. Jedynym powodem, dla którego mogę myśleć o problemie z klonowaną tablicą, nie jest informacja, że ​​zmodyfikowaliśmy oryginalną tablicę po klonowaniu (płytka kopia wchodzi wtedy do gry).

BTW Użyłem Java 1.6, mam nadzieję, że to nie jest problem.

Edytuj: Po prostu musimy zrozumieć, dlaczego ich płytka kopia zamiast głębokiej kopii tablicy wielowymiarowej. Przyjrzyjmy się 2 faktom:

  1. Podczas klonowania Obiekty są zawsze klonowane jako płytka kopia (kopia odniesienia obiektu), tylko typy natywne otrzymują prawdziwą kopię. In Java, what is a shallow copy?
  2. tablicy w Java jest rzeczywiście przedmiotem Is an array an object in java

Teraz połączenie 1 i 2, wiemy, że wielowymiarowa tablica w języku Java jest tylko przedmiotem, który ma odniesienie do innych obiektów tablicy.

Coś takiego jak ArrayObj -> {ArrayObj, ArrayObj, ArrayObj};

A ponieważ mamy Obiekty wewnątrz obiektów (kompozycja), mamy otrzymać płytką kopię zgodnie z regułą klonowania Javy.

+0

Ja wyjaśnię. Klonowanie rzeczywiście się zdarzyło, ale nie jest głębokie. – Bozho

Powiązane problemy