Tauschalgorithmus funktioniert nicht

Guten Abend,

ich frage mich gerade warum dieser Alghorithmus nicht die ersten Beiden Werte von a vertauscht:

public static void main(String[] args) {
	int [] value = new int [5];
	value[0]=1;
	value[1]=2;
	value[2]=3;
	tausche(value);
		for (int i=0; i<value.length; i++){
			System.out.println(value**);
		}

	}


	public static void tausche(int[] a) {
		int[] c = new int[a.length];
		c[0] = a[1];
		c[1] = a[0];
		for (int i = 2; i < a.length; i++){
			c** = a**;
		}
		a = c;
	}```

Der hier jedoch schon:

public static void main(String[] args) {
	int [] value = new int [5];
	value[0]=1;
	value[1]=2;
	value[2]=3;
	tausche(value);
	for (int i=0; i<value.length; i++){
		System.out.println(value**);
	}

}


public static void tausche(int[] a) {
	int c = a[0];
	a[0] = a[1];
	a[1] = c;
}```

Mir ist generell nicht klar, wann Methoden wirklich werte außerhalb der Methoden verändern und wann nicht. Bis jetzt deklariere ich Variablen die ich an mehreren Stellen verändern möchte immer außerhalb der Methoden direkt in der Klasse, sodass alle unabhängig voneinander darauf zugreifen können.

Hmm, ich versuche das mal zu erklären:

An die Methode tausche übergibst du tatsächlich nur eine Speicheradresse (z.B. 0xac8e0e). Dein paramater a und deine Variable value in deiner main haben also diesen Wert. Mithilfe dieser Adresse findet Java dein Objekt und du kannst damit arbeiten (d.h. Werte vom Array ändern). Wenn du aber später ein neues Array deinem Parameter a zuweist, dann änderst du tatsächlich nur die Speicheradresse, auf die a zeigt. Von dieser Änderung bekommt aber deine Variable value nichts mit und zeigt noch auf das Originale Array.

Java kennt nur „Call by Value“. Wenn man den ‚value‘ array an die Methode übergibt (der, um diesen Sachverhalt zu erklären, den denkbar ungünstigsten Namen hat :D) , kommt dort nicht der gesamte Array an, sondern nur der Wert einer Referenz auf diesen Array. Und der Wert dieser Referenz wird hier…

    public static void tausche(int[] a) {
        int[] c = new int[a.length];
...
        a = c; 
    }

… in der letzten Zeile geändert. Es gibt sicher anschauliche Beispiele, mit Schuhkästen oder Fernbedienungen, aber im Moment ist zu sehr Freitag Nachmittag, als das mit da was gutes einfallen würde :wink:

vll auch noch dazu:

http://wiki.byte-welt.net/wiki/Call_by_value_(Java)

@marco spielst du den Fernbedienungen auf Java von Kopf bis Fuß an ? :smiley:

Nicht bewußt nein, aber man könnte sich eine Metapher darüber vorstellen. Oder über „der Griff eines Koffers“ oder so, aber … da bin ich im Moment zu unkreativ.

(*sich fragend, was passiert, wenn ‚marc‘ und ‚marco‘ sich irgendwann mal (wieder?) einloggen, und feststellen, dass sie hunderte von ‚mentions‘ haben :smiley: *)

Ah, also ist das eine Besonderheit von wie mit Arrays umgegangen wird? Ich hab den Code aus dem Wiki verändert, sodass er ein Array benutzt und es wird wie erwartet 6 ausgegeben.

package ausprobieren;

public class CallbyValue {
	public static void main(String[] args) {
		   int [] x = {5};
		   // die variable x wird kopiert und somit nicht durch die methode verändert
		   doSomething(x);
		   // immer noch 5
		   System.out.println(x[0]);
		}
		 
		public static void doSomething(int [] x) {
		   x[0] = x[0]+1;
		}
}

Aber warum ist das hier dann kein Call by Reference? (welches es in Java ja nicht gibt) Weil die änderung nicht durch die Variable sondern durch die Speicherzuweisung stattfindet? Das verwirrt mich gerade.

Deine Methode zeigt immer noch auf das gleiche Array und du änderst den “Inhalt” dessen. Hier wäre das passende Beispiel du würdest in der Methode ein neues Array erstellen auf x.
Das würde keine Auswirkungen haben.

	public static void main(String[] args) {
		new CallByValue();
	}
	
	private CallByValue(){
		int[] arr = {5};
		change(arr);
		System.out.println(arr[0]);
		
	}

	private void change(int[] arr) {	
		arr[0] = 4;	
		arr = new int[]{2};
	}	
}```


Vielleicht noch ein anderes Beispiel:

Du hast ein Tier:

```public class Tier {	
	private String name;
	
	public Tier(String name){
		this.name = name;
	}

	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
}```

```public class Starter {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Tier tier = new Tier("WOLF");
		System.out.println(tier.getName()); //Hier Wolf
		changeTier(tier);
		System.out.println(tier.getName()); //Hier Wolf
		changeName(tier);
		System.out.println(tier.getName()); //Hier Hund

	}
	
		public static void changeTier(Tier tier){
		Tier neuesTier = new Tier("Gans");
		tier = neuesTier;
	}
	
	public static void changeName(Tier tier){
		tier.setName("Hund");
	}

}```

[QUOTE=pl4gu33]vll auch noch dazu:

http://wiki.byte-welt.net/wiki/Call_by_value_(Java)

@marco spielst du den Fernbedienungen auf Java von Kopf bis Fuß an ? :D[/QUOTE]

oweh… bei dem Wiki-Beitrag, da würd ich doch ganz energisch widersprechen !
Als alter Basic-Programmierer hab ich gelernt, du kannst in einer Funktion über die Funktionsparameter NICHTS zurückgeben, wenn der betreffende Parameter byVal ist …
ist er aber byRef, dann gelingt das.
ByVal heisst nämlich, dass man auf das Original des aufrufenden Programmteils keinen Zugriff hat, weil nur der Wert (Value) geliefert wurde.
Da man in Java aber sehr wohl die Inhalte der Originale der übergebenen Parameter verändern kann, wenn auch nicht deren Referenzen, ist das call byRef, generell und nie byVal (ausser die primitive), sorry.
Ich möchte das aber nicht wirklich diskutieren.
Wobei… im Grunde ist das ja in VB ja auch so, dass Objekte immer veränderbar sind, auch wenn byVal angegeben wird…
Vielleicht sind diese Begriffe byVal und byRef einfach ziemlich blöd.