Ist Java pass by reference oder pass by value?

swas

Mitglied
Hallo Leute,

ich hätte mal ne Frage zu Java und pass by reference (pbr) bzw. pass by value (pbv).
Was macht Java denn jetzt genau? Ich habe das Gefühl, dass es für bestimmte Objekte bzw. Datentypen pbr ist und für andere wiederrum pbv.
Ich habe einwenig im Internet gesucht und zwei Recht gute Erklärungen gefunden, die sich jedoch wiedersprechen (zumindest wenn ich sie richtig verstanden habe;)).

Erklärungen:
Java is Pass-by-Value, Dammit!
und
Pass-by-Value Please

Kann mir einer bitte sagen, welche der beiden Erklärungen die Richtige ist oder mir zumindest erklären wie Java das handhabt?

Gruß
swas
 
Java ist im Grunde eigentlich beides.
Bei primitiven Datentypen und String wird der Wert (pbv) mitgegeben und bei allem anderen die Referenz (pbr)
 
Hallo,

Java kann nur call / pass by Value. Auch Objekt-Referenzen werden by-Value übergeben...

Beispiel:
Java:
public class CallByValue {
  public static void main(String[] args) {
    String s= "a";
    f(s);
    System.out.println(s); //-> a und nicht! b
  }

  private static void f(String s) {
    s = "b";
  }
}

Dieses Beispiel gibt a aus, da die Zuweisung von "b" an s innerhalb von f keine Auswirkungen nach außen hat -> es gibt keinen Referenz-Operator wie in C/C++ der eine direkte Manipulation der Referenz erlauben würde.

Gruß Tom
 
Hallo!

Mein Vorredner hat ja schon ein einleuchtendes Beispiel gegeben. Da die Klasse String zuvor allerdings als Ausnahme beschrieben wurde, sei noch einmal darauf hingewiesen, dass das so auch mit beliebigen anderen Datentypen läuft - die Referenz wird sozusagen als Wert übergeben :)
 
Danke für Eure Antworten.

Was ich aber noch nicht ganz verstehe ist:
Wenn Java jetz rein call by Value ist, dann dürften doch Änderungen an einem Objekt in einer Methode nicht auf das "Quellobjekt" einwirken, richtig?
Wenn ich jetz aber z.B. folgendes mache:
Java:
public class BufferedReaderTest {

	public static void main(String[] args) {
		File f = new File("./test.txt");
		
		try {
			BufferedReader in = new BufferedReader(new FileReader(f));
			
			closeReader(in);
			
			System.out.println(in.readLine()); // hier entsteht die Exception
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void closeReader(BufferedReader buf) throws Exception {
		buf.close();
	}
	
}
Bekomme ich die IOException: Stream closed. Oder ist dies nur ein besonderer Fall.

Gruß
swas
 
Hallo,

Wenn Java jetz rein call by Value ist, dann dürften doch Änderungen an einem Objekt in einer Methode nicht auf das "Quellobjekt" einwirken, richtig?

Das verstehst du falsch... du kannst den Objektzustand natürlich auch bei call-by-value ändern, dass hat erstmal nichts mit call-by-reference zu tun... schau dir nochmal mein Beispiel an.

Call-by-value bedeutet in unserem Fall, dass du die Referenz (die du eben auch als Wert übergeben bekommst) nicht ändern kannst. Mit Referenz ist in meinem Beispiel der Inhalt von "s" gemeint. Hierbei ist in der Variablen s eine Referenz auf die String-Instanz "a" gespeichert. Wenn du nun s einer Methode als Parameter übergibst wird dieser Methode die Referenz in s als Wert übergeben. Du kannst also mit dieser Referenz arbeiten, Attribute auslesen, Methoden aufrufen etc.
Da du die Referenz auf "a" jedoch als "fixen" Wert übergeben bekommst kannst du diese Referenz (hier ist nicht das Objekt selbst gemeint sondern die Referenz darauf... (1)) nach außenhin nicht ändern. -> Es ist nicht möglich (2) die übergebene Referenz (s) innerhalb von f so zu manipulieren, dass diese nach f auf eine andere Instanz referenziert.

Noch ein Beispiel:
Java:
public class CallByValue {
	public static void main(String[] args) {
		Object a = new Object();
		Object b = a;
		f(a);
		System.out.println(a == b); //can never be false 
	}

	public static void f(Object o) {
		o = new Object(); //does not affect a or b
	}
}

Hier noch ein Beispiel zum verdeutlichen:
C++:
// CallByReferenceExample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>

void fV(char c){ //wir bekommen den Wert von c per Call by Value übergeben
	c='v';
}

void fR(char &c){ //wir bekommen die Wert von c per Call by Reference übergeben
	c='r';
}

int _tmain(int argc, _TCHAR* argv[])
{

	char c = 'a';
	std::cout << c << std::endl;
	fV(c);
	std::cout << c << std::endl;
	fR(c);
	std::cout << c << std::endl;
	return 0;
}

Ausgabe:
Code:
a
a
r //hier wurde der Wert tatsächlich nach außen hin verändert...

1) ...mal abgesehen davon das String aus unserem Beispiel Immutable ist, okay per Reflection kann man da was drehen... ;-)

(2) ...mal abgesehen von irgendwelchen nativen JNI Schweinereien oder einer "pseudo" Variante mit Arrays...

Gruß Tom
 
Zurück