Call by Value: Unterschied zwischen den Versionen

Aus EINI
Wechseln zu: Navigation, Suche
K
(Beispiel)
 
(17 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
Als '''Call by Value''' bezeichnet man den Mechanismus der Parameterübergabe von primitiven Datentypen. Sein Pendant ist der Mechanismus des [[Call by Reference]].
+
'''Call by Value''' bezeichnet die Übergabe von [[Parameter]]n von [[Primitiver Datentyp|primitiven Datentypen]].  
  
Dabei wird beim Aufruf einer Funktion der Wert einer Variable zuerst aufgelöst und dann direkt an die aufrufende [[Methode]] übergeben. Da die Parameter einer Funktion lokal auf dem [[Stack]] der [[Methode]] liegen, sind diese unabhängig von denen, die beim Aufruf der Methode verwendet wurden. Änderungen an den [[Parametervariable|Parametervariablen]] haben demnach keinen Einfluss auf die Werte der übergebenen Variablen innerhalb der aufrufenden Methode.
+
Bei [[Variablen]] mit [[Objekt|Objektdatentyp]] wird hingegen der [[Call by Reference]] verwendet.
  
= Verwendung =
+
Der  '''Call by Value''' funktioniert folgendermaßen: Beim Aufruf einer [[Methode]] wird der '''Wert''' einer Variablen zuerst aufgelöst und dann direkt an die aufgerufene Methode übergeben. Es wird also eine '''Kopie des Wertes''' der Variablen übergeben.
 +
 
 +
Da die '''Parameter''' einer Funktion [[Variable#Lokale Variable|lokal]] sind, sind diese unabhängig von denen, die beim Aufruf der Methode verwendet wurden. Innerhalb einer aufgerufenen Methode haben Änderungen an den [[Parametervariable|Parametervariablen]] demnach '''keinen Einfluss''' auf die Werte der übergebenen Variablen.
 +
 
 +
= Problematik =
 +
 
 +
Ein mangelndes Verständnis der '''Call by Value'''-Funktionalität von Methodenaufrufen führt häufig zu dem Fehler, dass ein Programmierer eine Funktion, die eine Berechnung durchführt, formuliert und erwartet, dass die übergebene Variable durch den Aufruf ihren Wert ändert.
 +
 
 +
Da jedoch durch '''Call by Value''' nur der Wert der Variablen, und nicht eine Referenz auf den Speicher der Variablen übergeben wird, hat diese Berechnung keinen Einfluss auf die Variable der aufrufenden Funktion. Dieser Fehler kann meistens dadurch behoben werden, dass der Wert der Variablen durch die Rückgabe der aufgerufenen Funktion ersetzt wird und die aufgerufene Funktion das Ergebnis ihrer Berechnung ''explizit'' zurück gibt (siehe Beispiel, unterer Code).
 +
 
 +
== Beispiel ==
  
 
Immer wenn eine Methode aufgerufen wird, werden übergebene Variablen zuerst aufgelöst und dann der resultierende Wert übergeben. Nehmen wir als Beispiel folgende zwei [[static | statische]] Methoden:
 
Immer wenn eine Methode aufgerufen wird, werden übergebene Variablen zuerst aufgelöst und dann der resultierende Wert übergeben. Nehmen wir als Beispiel folgende zwei [[static | statische]] Methoden:
<source lang="Java">
+
 
 +
<source lang="java">
 
public static void caller(){
 
public static void caller(){
 
     int i = 5;
 
     int i = 5;
 
     callee(i);
 
     callee(i);
 +
    System.out.println(i);
 
}
 
}
 
public static void callee(int a){
 
public static void callee(int a){
Zeile 16: Zeile 28:
 
</source>
 
</source>
  
Die Methode <code>caller()</code> deklariert eine <code>int</code> Variable <code>i</code> mit dem Wert 5. Beim Aufruf von <code>callee(int a)</code> wird die übergebene Variable <code>i</code> nun zuerst zum Wert 5 aufgelöst. Dann wird die Funktion <code>callee(int a)</code> mit dem Wert 5 aufgerufen. Der Aufruf <code>callee(i)</code> ist also in diesem Falle nicht zu unterscheiden von einem Aufruf <code>callee(5)</code>. Hier sieht man zudem den Grund für das Verhalten von '''Call by Value''':
+
Der unerfahrene Programmierer, der diesen Code schreiben mag, wird hier denken, die Ausgabe des Programmes (Zeile 4) sei '''10'''. Tatsächlich ist sie jedoch '''5'''.
  
Wenn eine Funktion wie <code>callee(int a)</code> direkt mit einem konstanten Wert, wie <code>5</code>, aufgerufen werden würde und Änderungen innerhalb der Methode Einfluss nach außen hätten, wie würde dieser Einfluss bei einem solchen Aufruf mit einer Konstanten wirken? Es wurde schließlich keine Variable als Repräsentation eines veränderbaren Wertes beim Aufruf übergeben. Was also soll sich beim Aufruf ändern? Für diesen Fall gibt es keine Semantik, die Sinn ergeben würde.
+
Die Methode <code>caller()</code> deklariert eine [[int]]-Variable <code>i</code> mit dem Wert 5 (Zeile 2). Beim Aufruf von der Methode <code>callee(int a)</code> wird die übergebene Variable <code>i</code> nun zuerst zum Wert 5 aufgelöst. Dann wird die Funktion <code>callee(int a)</code> mit dem Wert 5 aufgerufen.(Zeile 3) Der Aufruf <code>callee(i)</code> ist also in diesem Falle nicht zu unterscheiden von einem Aufruf <code>callee(5)</code>.
 +
Eine Funktion, die primitive Daten als Parameter erwartet, kann mit konstanten Werten wie <code>callee(5)</code> aufgerufen werden. Deshalb kann in diesem Fall ein Aufruf mit 5 keinen Einfluss auf die 5 haben, da der Ausdruck "5" konstant ist. Zeile 7 hat daher keinen Einfluss auf die Variablen der Funktion <code>caller()</code>. Daher lautet die Ausgabe logischerweise '''5'''.
  
Was tatsächlich passiert, ist, dass beim Aufruf einer Funktion ein neuer [[Stack#Stackframe | Stackframe]] für diesen Aufruf auf den [[Stack]] gelegt wird und die lokalen Parametervariablen innerhalb dieses Stackframes mit den übergebenen Werten initialisiert werden. Ein konstanter Aufruf von <code>callee(int a)</code> mit der Zahl 5 wäre also praktisch nicht zu unterscheiden von einer Methode, die folgendermaßen aussieht:
 
  
<source lang="Java">public static callee(){
+
Möchte man im Beispiel oben den Wert der Variablen <code>i</code> außerhalb der Funktion ändern, so wird man enttäuscht. Dies ist in [[Java]] mit primitiven Daten nicht möglich. Man benötigt eine Funktion mit einer [[Rückgabe]]. Das heißt die Funktion muss eine Eingabe erhalten, etwas berechnen und das Ergebnis der Berechnung ''explizit'' zurück geben. Der zurückgegebene Wert muss dann der Variablen als neuer Wert zugewiesen werden:
     int a = 5;
+
 
     a = a + 5;  
+
<source lang="java">
}</source>
+
public static void caller(){
 +
     int i = 5;
 +
     i = callee(i);
 +
}
 +
 
 +
public static int callee(int a){
 +
    return a + 5;
 +
}
 +
</source>

Aktuelle Version vom 26. September 2016, 19:28 Uhr

Call by Value bezeichnet die Übergabe von Parametern von primitiven Datentypen.

Bei Variablen mit Objektdatentyp wird hingegen der Call by Reference verwendet.

Der Call by Value funktioniert folgendermaßen: Beim Aufruf einer Methode wird der Wert einer Variablen zuerst aufgelöst und dann direkt an die aufgerufene Methode übergeben. Es wird also eine Kopie des Wertes der Variablen übergeben.

Da die Parameter einer Funktion lokal sind, sind diese unabhängig von denen, die beim Aufruf der Methode verwendet wurden. Innerhalb einer aufgerufenen Methode haben Änderungen an den Parametervariablen demnach keinen Einfluss auf die Werte der übergebenen Variablen.

Problematik

Ein mangelndes Verständnis der Call by Value-Funktionalität von Methodenaufrufen führt häufig zu dem Fehler, dass ein Programmierer eine Funktion, die eine Berechnung durchführt, formuliert und erwartet, dass die übergebene Variable durch den Aufruf ihren Wert ändert.

Da jedoch durch Call by Value nur der Wert der Variablen, und nicht eine Referenz auf den Speicher der Variablen übergeben wird, hat diese Berechnung keinen Einfluss auf die Variable der aufrufenden Funktion. Dieser Fehler kann meistens dadurch behoben werden, dass der Wert der Variablen durch die Rückgabe der aufgerufenen Funktion ersetzt wird und die aufgerufene Funktion das Ergebnis ihrer Berechnung explizit zurück gibt (siehe Beispiel, unterer Code).

Beispiel

Immer wenn eine Methode aufgerufen wird, werden übergebene Variablen zuerst aufgelöst und dann der resultierende Wert übergeben. Nehmen wir als Beispiel folgende zwei statische Methoden:

public static void caller(){
    int i = 5;
    callee(i);
    System.out.println(i);
}
public static void callee(int a){
    a = a + 5;
}

Der unerfahrene Programmierer, der diesen Code schreiben mag, wird hier denken, die Ausgabe des Programmes (Zeile 4) sei 10. Tatsächlich ist sie jedoch 5.

Die Methode caller() deklariert eine int-Variable i mit dem Wert 5 (Zeile 2). Beim Aufruf von der Methode callee(int a) wird die übergebene Variable i nun zuerst zum Wert 5 aufgelöst. Dann wird die Funktion callee(int a) mit dem Wert 5 aufgerufen.(Zeile 3) Der Aufruf callee(i) ist also in diesem Falle nicht zu unterscheiden von einem Aufruf callee(5). Eine Funktion, die primitive Daten als Parameter erwartet, kann mit konstanten Werten wie callee(5) aufgerufen werden. Deshalb kann in diesem Fall ein Aufruf mit 5 keinen Einfluss auf die 5 haben, da der Ausdruck "5" konstant ist. Zeile 7 hat daher keinen Einfluss auf die Variablen der Funktion caller(). Daher lautet die Ausgabe logischerweise 5.


Möchte man im Beispiel oben den Wert der Variablen i außerhalb der Funktion ändern, so wird man enttäuscht. Dies ist in Java mit primitiven Daten nicht möglich. Man benötigt eine Funktion mit einer Rückgabe. Das heißt die Funktion muss eine Eingabe erhalten, etwas berechnen und das Ergebnis der Berechnung explizit zurück geben. Der zurückgegebene Wert muss dann der Variablen als neuer Wert zugewiesen werden:

public static void caller(){
    int i = 5;
    i = callee(i);
}

public static int callee(int a){
    return a + 5;
}