Schleifenindex "by reference" / "by value"

  • Themenstarter Themenstarter trez
  • Beginndatum Beginndatum
T

trez

Gast
Beim Hacken für einen anderen Thread bin ich auf einen interessanten Effekt gestossen.
(Das ist eher eine Feststellung als eine Frage und möglicherweise auch für andere Anfänger interessant ;-) )

Offensichtlich werden auch in diesem Konstrukt die Primitives "by copy" und die Anderen "by reference" an den Schlaufenindex übergeben

Java:
int[][] array = new int[5][3];
// Bewirkt nichts. Eclipse warnt auch "The value of the local variable i is not used"
for (int[] ia : array) {
	for (int i : ia ) {
		i = 42;
	}
}
// Funktioniert
for (int[] ia : array) {
	for (int i=0; i<ia.length; i++) {
		ia[i] = 42;
	}
}
 
Moin,

Äh 😱 ... was genau willst Du uns sagen??

Java:
int[][] array = new int[5][3];
// Bewirkt nichts. Eclipse warnt auch "The value of the local variable i is not used"
for (int[] ia : array) {
	for (int i : ia ) {
		i = 42;
	}
}

// Funktioniert
for (int[] ia : array) {
	for (int i=0; i<ia.length; i++) {
		ia[i] = 42;
	}
}
(a) funktionieren tut beides !!
(b) die Warnung ist doch logisch! Du setzt 'n'-mal die Variable 'i' auf den Wert "42", benutzt 'i' aber nie!
(c) im zweiten Fall jedoch WIRD die Variable 'i' verwendet !!
EDIT
(d) "i = 42" und "ia = 42" sind was völlig verschiedenes :autsch:


Gruß
Klaus
 
Zuletzt bearbeitet:
[...]
Offensichtlich werden auch in diesem Konstrukt die Primitives "by copy" und die Anderen "by reference" an den Schlaufenindex übergeben[...]

Das ist Unfug, dein Code ist falsch. Die äquivalente for-Schleife zu deinem Code-Block mit den erweiterten for-Schleifen ist Folgende:

Java:
for (int[] ia : array) {
            for (int i=0; i<ia.length; i++) {
                i = 42;
            }
        }

Und wie man sieht, sieht man genauso wenig.

Das was du mit den erweiterten for-Schleifen erreichen wolltest ist wie folgt möglich:

Java:
        for (int[] ia : array) {
            int col = 0;
            for (int i : ia) {
                ia[col++] = 42;
            }
        }

for-schleife
 
Das ist Unfug, dein Code ist falsch. Die äquivalente for-Schleife zu deinem Code-Block mit den erweiterten for-Schleifen ist Folgende:
Java:
for (int[] ia : array) {
            for (int i=0; i<ia.length; i++) {
                i = 42;
            }
        }
Auch falsch. Die "Umsetzung" einer foreach-Schleife sieht eher so aus:
Java:
for (int[] ia : array) {
    for (int index=0; index<ia.length; index++) {
      int i = ia[index];
      i = 42;
     }
}
 
Auch falsch. Die "Umsetzung" einer foreach-Schleife sieht eher so aus:
Java:
for (int[] ia : array) {
    for (int index=0; index<ia.length; index++) {
      int i = ia[index];
      i = 42;
     }
}

Jipp, konnte nicht mehr editieren und war zu faul einen neuen Beitrag zu schreiben, da der Punkt hoffentlich rübergekommen war. 🙂
 
Zeilen 18-22 bewirken im Array gar nichts, Zeilen 27 - 31 setzen die Werte im Array.

Ich wollte genau das sagen was schon oben steht - es ist eine Feststellung, dass auf den Zeilen 4, 18 und 27 der Wert per Reference, aber auf den Zeilen 5, 19 und 28 per Copy an den Index übergeben wird.

Der Code ist sicher kein Unfug, denn er zeigt einen Effekt, der mir bei Parametern längst bewusst war, aber nicht im Zusammenhang mit for-Schleifen.

Das war mir nicht bewusst und wird wohl manch anderem Anfänger auch nicht bewusst sein. Da ein Forum auch ein Archiv ist, gehören IMHO auch Feststellungen dahin.

Java:
public class ForSchleifenVersuch {

	private static void printArr(int[][] iarr) {
		for (int[] ia : iarr) {
			for (int i : ia ) {
				System.out.printf( "%03d ", i );
			}
			System.out.println();
		}
		System.out.println();
	}

	public static void main(String[] args) {
		int[][] array = new int[5][3];
		System.out.println("Neu angelegter Array");
		printArr(array);
		// Geht nicht
		for (int[] ia:array) {
			for (int i : ia ) {
				i = 42;
			}
		}
		System.out.println();
		System.out.println("Erster Versuch");
		printArr(array);
		// Funktioniert
		for (int[] ia : array) {
			for (int i=0; i<ia.length; i++) {
				ia[i] = 42;
			}
		}
		System.out.println();
		System.out.println("Zweiter Versuch");
		printArr(array);
	}
}

Output:
Neu angelegter Array
000 000 000 
000 000 000 
000 000 000 
000 000 000 
000 000 000 


Erster Versuch
000 000 000 
000 000 000 
000 000 000 
000 000 000 
000 000 000 


Zweiter Versuch
042 042 042 
042 042 042 
042 042 042 
042 042 042 
042 042 042

PS: Aehm - falls sich jemand mit Unit-Tests auskennt - ich bin immer noch auf der Suche nach Lösungsvorschlägen
 
Zuletzt bearbeitet von einem Moderator:
Zeilen 18-22 bewirken im Array gar nichts, Zeilen 27 - 31 setzen die Werte im Array.

Ich wollte genau das sagen was schon oben steht - es ist eine Feststellung, dass auf den Zeilen 4, 18 und 27 der Wert per Reference, aber auf den Zeilen 5, 19 und 28 per Copy an den Index übergeben wird.

Ja bei den Zeilen 4, 18 und 27 arbeitest du auch mit einem Array, dieses ist laut Java Spezifikation ein Object -> "by reference". Wobei du bei den Zeilen 5, 19 und 28 mit int arbeitest einen primitiven Datentyp -> "by value"

Worin liegt die neue Erkenntnis? Primitives werden IMMER "by value" übergeben.
 
[...]
Der Code ist sicher kein Unfug, denn er zeigt einen Effekt, der mir bei Parametern längst bewusst war, aber nicht im Zusammenhang mit for-Schleifen.
[...]

Letzter versuch, deine Aussage ist immer noch nicht richtig. Du behauptest folgendes würde nicht funktionieren wg. call by value, call by reference und zeigst folgenden Code.

Java:
int[][] array = new int[5][3];
// Bewirkt nichts. Eclipse warnt auch "The value of the local variable i is not used"
for (int[] ia : array) {
	for (int i : ia ) {
		i = 42;
	}
}
// Funktioniert
for (int[] ia : array) {
	for (int i=0; i<ia.length; i++) {
		ia[i] = 42;
	}
}

Der Code ist semantisch nicht äquivalent und das hat nichts mit call by value/reference zu tun. Deine erweiterten for-Schleifen sind identisch zu dem was Natac korrigiert postete. Der Unterschied zwischen deiner normalen for-Schleife wird hier sehr deutlich.

Java:
for (int[] ia : array) {
    for (int index=0; index<ia.length; index++) {
      int i = ia[index];
      i = 42;
     }
}

Des Weiteren gab es folgenden Code der genau das mit den erweiterten for-schleifen erreicht was du ursprünglich wolltest.

Java:
        for (int[] ia : array) {
            int col = 0;
            for (int i : ia) {
                ia[col++] = 42;
            }
        }

Dieser entspricht vom Verhalten dem folgenden Stück

Java:
for (int[] ia : array) {
    for (int index=0; index<ia.length; index++) {
      int i = ia[index];
      ia[index] = 42;
     }
}

Das Ergebnis daraus ist für jede Eingabe identisch zu deiner for-Schleifen-Variante.

[Java]
for (int[] ia : array) {
for (int i=0; i<ia.length; i++) {
ia = 42;
}
}
[/code]


Das einzige Problem was es hier gibt ist das du glaubst deine geposteten Code-Schnipsel seien identisch und schiebst das auf ein Problem mit call by value/reference.
 
Worin liegt die neue Erkenntnis? Primitives werden IMMER "by value" übergeben.
Die Erkenntnis ist doch schlicht und einfach die, dass es sich im Kontext einer for-Schlaufe, was nicht als "Übergabe" im Sinne von f(x) erkennbar ist, eben doch um eine handelt.

Hm - wieso zerreisst ihr hier jetzt eine Feststellung die Anfängern weiterhelfen soll und zum Thema JUnit äussert sich niemand?
 
Zuletzt bearbeitet von einem Moderator:
Sorry, aber jeder meiner Posts war richtig wenn man es verstehen will. Wer Profi ist, wird es halt nicht mehr nachvollziehen können aber für Anfänger ist nicht nachvollziehbar, warum Java einen Teil by Reference und einen anderen Teil per Value macht, sogar dann wenn es sich NICHT um eine Paramterübergabe handelt.

Was das mit JUnit zu tun hat: Feststellungen wie diese hier werden vorwärts und rückwärts zerrissen aber auf die für mich wichtigere Frage, die hier, kommt keine Antwort

Nehmt doch die Herausforderung an ....
 
Okay, einen Versuch mach ich noch:

Wir haben folgendes array:
Java:
int[] array = {1,2,3,4,5};

Dein erster Code-Schnipsel:
Java:
        for (int i : array ) {// = for(int x=0;x<array.length;x++){ int i = array[x];
            i = 42;
        }
Verändert das Array NICHT. Es ist immernoch 1,2,3,4,5. Eben weil du nur die Variable i überschreibst. Diese enthält zwar den Wert an der Stelle x, aber sie "aktualisiert" ihn nicht, wenn du die "i" änderst. Zu beachten ist hier auch, dass "i" NICHT der index ist. Ähnlich wäre:
Java:
List<String> list = new ArrayList();
String s = "hello";
list.add(s); //s wird by value übergeben. Die add-Methode erhält eine Kopie.
s = "world";//ändert NICHT die Liste, sondern nur den Variableninhalt von s

Dein zweiter Code (vereinfacht - ich habe statt "i" wieder "x" für den index genommen, wie im obigen Code auch):
Java:
        for (int x=0; x<array.length; x++) {
           array[x] = 42; 
        }
Das Array ist hinterher 42,42,42,42,42. Da du an jedem index "x" den Wert im Array auf den 42 setzt. Zu beachten ist her, dass die Variable "i" aus dem ersten Code-Schnipsel gar nicht auftaucht. Wollten wir ein "i" einfügen, das sich genauso wie im ersten Code-Schnipsel verhält, würde das so aussehen:
Java:
  for (int x=0; x<array.length; x++) {
           array[x] = 42; 
           int i = x; // sinnlos, da mit i nichts gemacht wird.
        }

Ich denke dich verwirrst die Tatsache, dass du in beiden Code-Schnipseln eine Variable "i" verwendest, die aber jeweils für einen völlig anderen Wert steht. Denk nochmal drüber nach. 😉

PS: Dieser Artikel könnte vielleicht für dich interessant sein.
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben