2012-02-16 15 views
14

Mi chiedo se il seguente ciclo crea una copia dell'oggetto, anziché darmi un riferimento. Il motivo è perché il primo esempio non assegna i miei oggetti array, ma il secondo sì. OggettiJava: ciclo For-Each e riferimenti

MyObject objects[] = new MyObject[6]; 
for (MyObject o: objects) { 

    o = new MyObject(); 
} 

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    objects[i] = new MyObject(); 
} 
+0

C'è davvero una sintassi del ciclo for come la prima è presente in java? –

+0

@ChandraSekhar: [per ogni ciclo java] (http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html). – RanRag

+0

@ChandraSekhar RanRag ha ragione. Tuttavia, ciò non è pertinente alla domanda.Forse l'OP ha appena riscritto il suo codice, non copia/incolla e quindi pensato nella sua lingua preferita. –

risposta

15

Java funziona un po 'diverso rispetto a molte altre lingue. Quello che o è nel primo esempio è semplicemente un riferimento all'oggetto.

Quando si dice o = new MyObject(), si crea un nuovo oggetto di tipo MyObject e riferimenti o per l'oggetto, mentre prima o riferimento objects[index].

Cioè, gli oggetti [indice] stesso sono solo un riferimento a un altro oggetto in memoria. Quindi, per impostare gli oggetti [indice] su un nuovo oggetto MyObject, è necessario modificare il punto in cui gli oggetti [indice] puntano, il che può essere fatto solo utilizzando gli oggetti [indice].

Image: (le mie terribili abilità vernice: D)

enter image description here

Spiegazione: Questo è più o meno come funziona la gestione della memoria Java. Non esattamente, in ogni caso, ma grosso modo. Hai oggetti, che fa riferimento a A1. Quando si accede alla matrice di oggetti, si inizia dal punto di riferimento iniziale (A1) e si spostano in avanti i blocchi X. Ad esempio, l'indice di riferimento 1 ti porta a B1. B1 quindi ti dice che stai cercando l'oggetto in A2. A2 ti dice che ha un campo situato in C2. C2 è un numero intero, un tipo di dati di base. La ricerca è fatta

o non fa riferimento a A1 o B1, ma C1 o C2. Quando dici new ..., creerà un nuovo oggetto e lo metterà lì (ad esempio, nello slot A3). Non influenzerà A1 o B1.

Fammi sapere se riesco a chiarire un po 'le cose.

+0

Certo, questo rende senziente. Quindi nel primo esempio, o è un po 'come un puntatore C++, in quanto è di per sé una variabile, e quindi il suo valore è l'indirizzo di un'altra variabile. Quindi, quando assegna qualcosa ad esso, viene impostata la variabile, piuttosto che a cosa sta puntando. Grazie! – rhughes

+0

Esattamente: D A differenza di C++, Java non ha molto in termini di controlli dei puntatori e così via. Le variabili fanno riferimento ai luoghi in memoria, e '=' li rinvia. Non è possibile creare una nuova variabile a cui si fa riferimento. Tuttavia, puoi cambiare questa variabile. Se 'o' è già inizializzato e' o.x' è un campo, puoi cambiare i punti 'o.x', riassegnando' o.x'. –

3

Il primo non alloca la matrice perché foreach cicli iterare sugli elementi di una collezione.

Quando si inserisce il ciclo foreach, non ci sono elementi nella raccolta, è solo un array vuoto inizializzato alla dimensione 6, quindi nessun oggetto verrà aggiunto all'array.

Inoltre, si noti che, anche se si ha elementi nella matrice del circuito foreach non assegnare sopra di essi:

o = new MyObject(); 

sostanzialmente significa assegnare ai o una nuova istanza di MyObject, ma o si è neanche parte dell'array objects è solo un contenitore temporaneo utilizzato per iterare sugli elementi dell'array, ma in questo caso non ce ne sono.

+0

Non è veramente vuoto, ha solo 6 valori nulli all'interno. Altrimenti, buona risposta. +1 –

+0

vuoto nel senso che non ci sono elementi di 'MyObject' al suo interno. –

+0

Penso che stiamo dicendo la stessa cosa con parole diverse. –

8

risposta breve: sì, c'è qualcosa come una copia in corso.

La risposta lunga: Il ciclo Java foreach che hai postato è zucchero sintattico per

MyObject objects[] = new MyObject[6]; 

Iterator<MyObject> it = objects.iterator(); 
while (it.hasNext()) { 
    MyObject o = it.next(); 
    // The previous three lines were from the foreach loop 

    // Your code inside the foreach loop 
    o = new MyObject(); 
} 

quanto private degli zuccheri mostra la versione, l'impostazione di un riferimento pari a qualcosa all'interno di un ciclo foreach non cambia il contenuto del array.

2

Gli oggetti vengono "copiati" solo quando si specifica esplicitamente di voler clonare un oggetto (e questo oggetto implementa esplicitamente la funzione di clonazione).

Sembra confondere riferimenti e nomi.

Nel primo esempio, all'interno di un foreach, la variabile locale o si riferisce all'area della memoria è memorizzato un oggetto da objects. Quando si esegue o = new MyObject(), un nuovo oggetto MyObject viene inizializzato in un'altra area della memoria, quindi il riferimento o viene riscritto per puntare su questa nuova area di memoria.

Nel secondo esempio, scrivendo objects[i] = new MyObject(), stai dicendo che il riferimento objects[i] deve essere riscritto, non una variabile locale o.

4

Ho aggiunto un commento a ciascun esempio per chiarire cosa sta succedendo.

Primo esempio:

MyObject objects[] = new MyObject[6]; 
for(MyObject o: objects) { 

    // Construct a new object of type MyObject and assign a reference to it into 
    // the iteration variable o. This has no lasting effect, because the foreach 
    // loop will automatically assign the next value into the iteration variable 
    // in the the next iteration. 
    o = new MyObject(); 
} 

Secondo esempio:

MyObject objects[] = new MyObject[6]; 
for(int i = 0; i < objects.length; i++) { 

    // Construct a new object of type MyObject and store a reference to it into the 
    // i-th slot in array objects[]: 
    objects[i] = new MyObject(); 
} 
+0

Non verrà compilato affatto, in quanto non è una parola chiave in Java, È necessario inserire i due punti (:) lì. –

+0

Ho appena copiato il codice originale dell'utente prima che fosse modificato e l'ho perso. Detto questo, non cambia il punto della mia risposta. –

+0

Chiunque avrebbe dovuto Igor dire perché lo hanno fatto. Il feedback negativo è inutile se non offri spiegazioni per miglioramenti. Igor, ho il sospetto che tu sia a causa della mancanza di profondità. –

0

prima cosa che voglio è detto che gli array non lunghezza zero sono sempre mutable.And all'interno del ciclo foreach

for(MyObject o in objects) 

quello che fa è in ogni iterazione funziona come segue.

o = objects[0] // first iteration 
o = objects[1] // 2nd iteration 

Ma nel tuo caso si assegna un altro oggetto al riferimento o. Non agli oggetti nell'array. È semplicemente come seguire.

ObjeMyObject objects[] = new MyObject[6]; 
MyObject o = Object[0]; 
0 = new MyObject(); 

Ma gli oggetti originali [0] puntano ancora a un oggetto nullo.

0

Ogni volta che si utilizza l'operatore "nuovo" JVM creerà una nuova istanza e verrà assegnato all'operando di sinistra dell'operatore di assegnazione. non ha importanza per ogni ciclo o ciclo. In per ogni ciclo per (MyObject O: Object) viene creato quando solo che sarà di MyObject non sarà istanziata ed i valori della matrice Object sarà mantenere la copia in O come

O = Object[0] 
O = Object[1] 
O = Object[2] 
O = Object[3] 
O = Object[4] 
O = Object[5] 
O

Non abbiamo bisogno di prendere cura di aumentare il contatore, questa è la bellezza di per ogni ciclo.