2012-02-02 14 views
10

Modifica 2: Di seguito è riportato un frammento di codice basato sulla risposta di DuffyMo che illustra come aggirare i limiti della clonazione per gli array multidimensionali mediante System.arraycopy.Come clonare un array multidimensionale in java?

import java.util.Arrays; 

public class Randar { 
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
private static int[][] arrayChanges = new int[arrayMaster.length][2]; 

public Randar() { 

} 
public static void main(String[] args) { 
    arrayChanges[0][0] = 0; 
    resetArrays(arrayChanges, arrayMaster); 
    arrayChanges[0][0] = 0; 

    System.out.format("arrayMaster: %s, arrayChanges: %s", Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges)); 
} 


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) { 
for (int a=0; a< arrayMaster.length; a++) { 
System.arraycopy(arrayMaster[a], 0, arrayChanges[a], 0, arrayMaster[a].length); 
} 
// arrayChanges = arrayMaster.clone(); will NOT work as expected 
} 
} 

[domanda originale] Che cosa è un modo semplice per (completamente) clonare un array multidimensionale in java? Questo programma illustra il mio problema.

import java.util.Arrays; 

public class Randar { 
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
static private int[][] arrayChanges = arrayMaster; 

public static void main(String[] args) { 
    arrayChanges[0][0] = 0; 
    resetArrays(); 

    System.out.format("arrayMaster: %s, arrayChanges: %s",Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges)); 
} 


public static void resetArrays() { 
arrayChanges = arrayMaster.clone(); 
} 

} 

Quando si esegue il codice sopra riportato, arrayMaster cambia così come arrayChanges, contrariamente alle mie intenzioni. Pensando che ho potuto clonare ogni singolo membro matrice bidimensionale di arrayMaster, ho cercato di aggirare il problema con questo:

for (int iter = 0; iter < arrayMaster.length; iter++) { 
    arrayChanges[iter] = arrayMaster[iter].clone(); 
    } 

ma quando ho eseguito il codice che dà un NullPointerException per qualche motivo. Sta scrivendo un metodo che scorre attraverso i singoli valori interi degli array, la mia unica opzione?

Grazie.

MODIFICA 1: Questo non risolve il problema.

import java.util.Arrays; 

public class Randar { 
public int[][] arrayMaster = {{6,1}, {10,1}, {1,1}}; 
private int[][] arrayChanges = arrayMaster.clone(); 

public Randar() { 

} 
public static void main(String[] args) { 
    Randar Randar1 = new Randar(); 
    Randar1.arrayChanges[0][0] = 0; 
    resetArrays(Randar1.arrayChanges, Randar1.arrayMaster); 
    Randar1.arrayChanges[0][0] = 0; 

    System.out.format("arrayMaster: %s, arrayChanges: %s",  Arrays.deepToString(Randar1.arrayMaster), Arrays.deepToString(Randar1.arrayChanges)); 
} 


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) { 
/*for (int a=0; a< arrayMaster.length; a++) { 
System.arraycopy(arrayMaster[a].clone(), 0, arrayChanges[a], 0, arrayMaster[a].length); 
} */ 
arrayChanges = arrayMaster.clone(); 
} 
} 

risposta

13

quando viene eseguito il codice di cui sopra, arrayMaster cambia così come arrayChanges, contrariamente alle mie intenzioni.

La linea

static private int[][] arrayChanges = arrayMaster; 

è il colpevole. Questa riga rende arrayChanges e arrayMaster punto allo stesso oggetto, quindi una modifica a uno dei due è visibile quando si accede all'oggetto da entrambi.

EDIT: Quello che accade ogni volta che si clona una dimensione di un array multidimensionale

Come Eric Lippert explains, un array è concettualmente un elenco di variabili. Se si assegna semplicemente un'altra variabile per puntare allo stesso array a la static private int[][] arrayChanges = arrayMaster;, non si è modificato affatto il set di variabili. Non hai creato nuove variabili ad eccezione di arrayChanges, quindi non hai più memoria dal sistema operativo/JVM, quindi qualsiasi modifica apportata a arrayMaster viene applicata a arrayChanges e viceversa.

Ora diamo un'occhiata a una matrice bidimensionale. In Java, un array bidimensionale è un elenco di variabili che ha la proprietà che ciascuna di queste variabili fa riferimento a un array unidimensionale. Quindi, ogni volta che cloni una matrice bidimensionale, crei una nuova lista di variabili, ciascuna puntata nello stesso punto in cui le vecchie variabili puntano. Quindi, hai guadagnato un po 'di tempo in quanto puoi scrivere in modo sicuro arrayChanges[0] = new int[10] senza influenzare arrayMaster, ma non appena si inizia a fare riferimento a arrayChanges[i][j], si fa ancora riferimento agli stessi array di secondo livello con riferimenti arrayMaster. Che cosa si vuole veramente per deep-copia una matrice bidimensionale di interi è

public static int[][] deepCopyIntMatrix(int[][] input) { 
    if (input == null) 
     return null; 
    int[][] result = new int[input.length][]; 
    for (int r = 0; r < input.length; r++) { 
     result[r] = input[r].clone(); 
    } 
    return result; 
} 

a coloro che possono guardare a questa risposta in futuro: sì, è meglio sostituire int con T qui e fare il metodo generico, ma a tale scopo un metodo di copia in profondità più concreto è più semplice da spiegare bene.

+0

Grazie per la risposta. Ho riscritto questo per raggruppare tutti i valori in una classe e non volevo dichiarare un'istanza di un oggetto, quindi sì, quello era un problema. Tuttavia, il problema persiste anche con codice scritto correttamente, come descritto qui [collegamento] (http://www.crazysquirrel.com/computing/java/basics/multidimensional-array-cloning.jspx) – vancan1ty

+0

Il problema non è la staticità affatto. Il problema è che i due nomi 'arrayChanges' e' arrayMaster' si riferiscono allo stesso oggetto. Hai fatto una copia superficiale quando hai dichiarato 'arrayChanges'. Vedi http://en.wikipedia.org/wiki/Object_copy per quale copia superficiale è. –

+0

@ user1184054 Si prega di inviare il codice appena scritto correttamente alla domanda. –

16

clone esegue una copia "superficiale". Cioè, l'array più esterno è duplicato, ma i valori memorizzati in esso sono invariati. Quindi se hai A1 = {B1, B2, B3} e cloni quello in A2, il contenuto iniziale di A2 sarà {B1, B2, B3}. Se cambi A1 in {C1, B2, B3} allora A2 rimarrà invariato, ma se cambi il contenuto di B1 (senza sostituirlo) allora A2 "vedrà" quel cambiamento.

Per ottenere ciò che si desidera, è necessario eseguire il ciclo attraverso l'array esterno e gli elementi di tale array esterno (che sono le matrici interne) da clone.

Pidgin Java:

int[][] A2 = A1.clone(); 
for (int i = 0; i < A2.length; i++) { 
    A2[i] = A2[i].clone(); 
} 
Problemi correlati