For-Each e Pointers in Java [duplicato]
Domanda
Questa domanda ha già una risposta qui:
Ok, quindi sto tentando di scorrere una ArrayList e rimuovere un elemento specifico. Tuttavia, sto riscontrando dei problemi nell'uso della struttura simile a For-Each. Quando eseguo il seguente codice:
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(String t : arr)
{
t = " some other value "; //hoping this would change the actual array
}
for(String t : arr)
{
System.out.println(t); //however, I still get the same array here
}
La mia domanda in, come posso fare 't' un puntatore a 'arr' in modo da poter cambiare i valori in un ciclo for-each? So che potrei scorrere l'ArrayList usando una struttura diversa, ma questa sembra così pulita e leggibile, sarebbe bello poter rendere 't' un puntatore.
Tutti i commenti sono apprezzati! Anche se dici che dovrei semplicemente succhiarlo e usare un costrutto diverso.
Soluzione
Penso che l'approccio migliore potrebbe essere quello di utilizzare un ciclo for.
ArrayList<String> arr = new ArrayList<String>();
for (int i = 0; i < arr.size(); i++) {
String t = arr.get(i);
if (// your condition is met) {
arr.set(i, "your new value");
}
}
Altri suggerimenti
Il problema è che stai provando a cambiare il riferimento t
con ambito loop per lasciarlo puntare a una nuova istanza String. Questo non funzionerà. Non fa riferimento alla voce effettiva nell'arraylist. Devi modificare il valore effettivo del riferimento. Se String
fosse mutabile e fornisse un metodo fittizio set ()
, in teoria potresti farlo
for (String t : arr) {
t.set("some other value");
}
o giù di lì, ma non è possibile in quanto è immutabile. Meglio ottenere un handle dell'entrypoint nell'array stesso usando il normale ciclo for
:
for (int i = 0; i < arr.size(); i++) {
arr.set(i, "some other value");
}
Se insisti nell'uso del ciclo for
migliorato, devi sostituire String
con StringBuilder
, che è modificabile:
for (StringBuilder t : arr) {
t.delete(0, t.length()).append("some other value");
}
Ricorda, Java è pass-by-value, non pass-by-reference.
Per-ciascuno non ti dà un puntatore indice, quindi non puoi semplicemente usarlo per cambiare un valore immutabile.
Utilizza un ciclo for con un indice o usa un tipo mutabile (come StringBuffer, non String)
Un array di oggetti (come stringhe) in Java è un blocco contiguo contenente una serie ordinata di riferimenti. Pertanto, quando si dispone di un array di 4 stringhe, ciò che realmente si ha sono 4 riferimenti memorizzati nell'array e 4 oggetti stringa che si trovano all'esterno dell'array ma a cui fanno riferimento i suoi 4 elementi.
Quello che fa il costrutto for-each in Java è creare una variabile locale e, per ogni iterazione, copiare in quella variabile locale il riferimento dalla cella dell'array che corrisponde a quella iterazione. Quando imposti la variabile loop ( t = " qualche altro valore "
) stai inserendo un riferimento a una nuova stringa, " qualche altro valore "
, nel locale variabile t, non nella matrice.
I contrasti con alcune altre lingue (come Perl) in cui la variabile loop si comporta come un alias dell'elemento array / list stesso.
Il tuo codice viene riscritto dal compilatore come qualcosa del genere:
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for (final Iterator <String> i = arr.iterator(); i.hasNext();) {
String t;
t = i.next();
t = " some other value "; // just changes where t is pointing
}
Per fare quello che vuoi, dovresti scrivere il ciclo for in questo modo:
for (final ListIterator<String> i = arr.iterator(); i.hasNext();) {
final String t;
t = i.next();
i.set("some other value");
}
Iterator non ha il metodo set, solo ListIterator.
Fondamentalmente si desidera rimuovere la stringa t dall'elenco arr. Basta fare un arr.remove (t) e potresti aver finito. Ma non puoi farlo mentre stai ripetendo lo stesso elenco. Otterrai un'eccezione se provi a modificare l'elenco in questo modo.
Hai due opzioni:
- clonare l'elenco, scorrere il clone e rimuovere la stringa "specifica" dall'elenco originale
- crea un elenco per eliminare i candidati, aggiungi tutte le stringhe "specifiche" a tale elenco e, dopo aver ripetuto l'elenco originale, esegui l'iterazione nel cestino e rimuovi tutto ciò che hai raccolto qui dall'elenco originale.
L'opzione 1 è il facilitatore, il clone può essere creato come:
List<String> clone = new ArrayList<String>(arr);
Sembra che tu capisca male come funzionano gli oggetti / i riferimenti in Java, il che è piuttosto fondamentale per usare il linguaggio in modo efficace. Tuttavia, questo codice qui dovrebbe fare quello che vuoi (scusa per la mancanza di spiegazioni):
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(int i = 0; i < arr.size(); i++)
{
arr.set(i, " some other value "); // change the contents of the array
}
for(String t : arr)
{
System.out.println(t);
}
Credo che questo non sia correlato a immutabile o mutevole.
t = " some other value "; //hoping this would change the actual array
t non contiene il riferimento all'oggetto reale. Java copia il valore dall'arraylist e lo inserisce in t in modo che il valore dell'elenco di array non abbia effetto.
HTH
Questa è stata risposta bene. Ecco ancora il mio suggerimento. La variante all'interno del loop è visibile solo lì. Non sarà visto al di fuori del ciclo. Puoi fare t.set ()
se non fosse String
.
Usa un StringBuffer
piuttosto che semplici stringhe. In questo modo la stringa all'interno è mutabile.
Le stringhe sono immutabili. Se avessi un tipo mutabile come StringBuilder / Buffer, potresti cambiare la stringa nella tua iterazione. Hai dei riferimenti, ricorda.