Czy wywołanie clone () w tablicy również klonuje jej zawartość?

92

Jeśli wywołam clone()metodę na tablicy obiektów typu A, w jaki sposób sklonuje jej elementy? Czy kopia będzie odnosić się do tych samych obiektów? A może wezwie (element of type A).clone()każdego z nich?

Szymon
źródło
3
Musisz wywołać clone na każdym elemencie.
Peter Lawrey

Odpowiedzi:

77

clone()tworzy płytką kopię. Co oznacza, że ​​elementy nie zostaną sklonowane. (A co, jeśli nie wdrożyli Cloneable?)

Możesz użyć Arrays.copyOf(..)do kopiowania tablic zamiast clone()(chociaż klonowanie jest dobre dla tablic, w przeciwieństwie do czegokolwiek innego)

Jeśli chcesz głębokiego klonowania, sprawdź tę odpowiedź


Mały przykład ilustrujący płytkość, clone()nawet jeśli elementy są Cloneable:

ArrayList[] array = new ArrayList[] {new ArrayList(), new ArrayList()};
ArrayList[] clone = array.clone();
for (int i = 0; i < clone.length; i ++) {
    System.out.println(System.identityHashCode(array[i]));
    System.out.println(System.identityHashCode(clone[i]));
    System.out.println(System.identityHashCode(array[i].clone()));
    System.out.println("-----");
}

Wydruki:

4384790  
4384790
9634993  
-----  
1641745  
1641745  
11077203  
-----  
Bozho
źródło
2
A jeśli miałbyś to zrobić, osobiście System.arrayCopy
użyłbym
1
clone()jest dobrą opcją do stosowania z tablicami… prawie wyłącznie. Bloch wspomina, że ​​używałby go tylko do tablic i nic więcej. System.arrayCopyjest w porządku. Arrays.copyOf(..)to kolejna alternatywa, która jest łatwiejsza w użyciu.
Bozho
Cofam to - Arrays.copyOfużyłbym :-) Ma sygnaturę metody, która upraszcza zmienne (tak, ogranicza cię, ale jest idealna w większości przypadków) iw moim JDK przynajmniej jest zaimplementowana przy użyciu i System.arrayCopytak. Dzięki za tę wskazówkę!
corsiKa
@Bozho, z Twojego np. array [i] i clone [i] będą odnosić się do tego samego obiektu, więc pierwsze dwa sysouty są takie same. Ale tablica [i] .clone odnosiłaby się również do samej tablicy [i], więc dlaczego tablica [i] .clone () zwraca inną wartość kodu skrótu?
abhihello123
@weakstudent, array[i].clone()NIE odnosi się do array[i]. To właśnie pokazuje ta część przykładu.
Dathan
19

Jeśli wywołam metodę clone () na tablicy obiektów typu A, w jaki sposób sklonuje ona swoje elementy?

Elementy tablicy nie zostaną sklonowane.

Czy kopia będzie odnosić się do tych samych obiektów?

Tak.

A może wywoła (element typu A) .clone () dla każdego z nich?

Nie, nie będzie odwoływać clone()się do żadnego z elementów.

Bludzee
źródło
6

Tablica 1D prymitywów kopiuje elementy podczas klonowania. Kusi nas to do sklonowania tablicy 2D (Array of Arrays).

Pamiętaj, że klon tablicy 2D nie działa z powodu płytkiej implementacji kopii clone().

public static void main(String[] args) {
    int row1[] = {0,1,2,3};
    int row2[] =  row1.clone();
    row2[0] = 10;
    System.out.println(row1[0] == row2[0]); // prints false

    int table1[][]={{0,1,2,3},{11,12,13,14}};
    int table2[][] = table1.clone();
    table2[0][0] = 100;
    System.out.println(table1[0][0] == table2[0][0]); //prints true
}
Thamme Gowda
źródło
1
Mówisz mi, że mogę clonetablicę prymitywów 1D i uzyskać głęboką kopię? To jest tak niesamowite! Radzą sobie dobrze Arrays.copyOfRange(), System.arraycopy()!
Janez Kuhar
1
Yessssss! Tablica 1D prymitywów jest kopiowana po sklonowaniu tablicy
Thamme Gowda
1
Zwróć uwagę, że Thamme Gowda N mówi „prymitywy”. Klony tablic obiektów będą po prostu klonem odniesień.
Kristiaan
ponieważ prymitywy nie mają stanu, są z natury niezmienne. Nie możesz zrobić płytkiej kopii prymitywów, ponieważ nie ma odniesienia
Xerus
5

Klon jest płytką kopią tablicy.

Ten kod testowy drukuje:

[1, 2] / [1, 2]
[100, 200] / [100, 2]

ponieważ MutableIntegerjest on współdzielony w obu tablicach jako objects[0]i objects2[0], ale możesz zmienić odwołanie objects[1]niezależnie od objects2[1].

import java.util.Arrays;                                                                                                                                 

public class CloneTest {                                                                                                                                 
    static class MutableInteger {                                                                                                                        
        int value;                                                                                                                                       
        MutableInteger(int value) {                                                                                                                      
            this.value = value;                                                                                                                          
        }                                                                                                                                                
        @Override                                                                                                                                        
        public String toString() {                                                                                                                       
            return Integer.toString(value);                                                                                                              
        }                                                                                                                                                
    }                                                                                                                                                    
    public static void main(String[] args) {                                                                                                             
        MutableInteger[] objects = new MutableInteger[] {
                new MutableInteger(1), new MutableInteger(2) };                                                
        MutableInteger[] objects2 = objects.clone();                                                                                                     
        System.out.println(Arrays.toString(objects) + " / " + 
                            Arrays.toString(objects2));                                                                
        objects[0].value = 100;                                                                                                                          
        objects[1] = new MutableInteger(200);                                                                                                            
        System.out.println(Arrays.toString(objects) + " / " + 
                            Arrays.toString(objects2));                                                               
    }                                                                                                                                                    
}                                                                                                                                                        
Simon Nickerson
źródło