Call By Value nennt man die in Java realisierte Form des Methodenaufrufs, bei dem Kopien von Werten und nicht die Werte selbst als Parameter übergeben werden.

Eine Variable stellt bekanntlich eine Referenz auf eine Speicherstelle dar. Soll der Wert der Speicherstelle in einer Methode bearbeitet werden, so wird beim Methodenaufruf der Inhalt der Speicherstelle, also der Wert kopiert und diese Kopie als Parameter an die Methode übergeben. Das bedeutet, dass der Originalwert unbeeinflusst bleibt. Das folgende Beispiel zeigt dies dadurch, dass die Ausgaben vor und nach dem Methodenaufruf identisch sind. Innerhalb der Methode werden lediglich die Werte der Parameter getauscht und der eventuell beabsichtigte Tausch der Variablen ist fehlgeschlagen.

public class CallByValue {

    public static void main(String[] args) {
        int a = 0;
        int b = 100;
        System.out.println("a: " + a + ", b: " + b);
        pseudoSwapInt(a, b);
        System.out.println("a: " + a + ", b: " + b);
    }

    private static void pseudoSwapInt(int pA, int pB) {
        int temp = pA;
        pA = pB;
        pB = temp;
        System.out.println("pA: " + pA + ", pB: " + pB);
    }
}

Selbstverständlich gilt dies nicht nur für primitive Datentypen, sondern auch für Referenztypen. Wie aber verhält es sich in einem solchen Fall mit deren Eigenschaften? Natürlich genauso, da die Parameter Kopien der Referenz, also des Verweises auf die Speicheradresse, darstellen. Original-Variable und Parameter zeigen also auf die selben (nicht nur gleichen) Werte. Innerhalb der Methode pseudoSwap() werden im Beispiel also nur die Zeiger auf die Speicherstellen beider Point-Objekte getauscht. Die Objekte selbst bleiben mit ihren Eigenschaften an den selben Speicherstellen unverändert erhalten.

import java.awt.Point;

public class Call_by_Value2 {

    public static void main(String[] args) {
        Point p1 = new Point(0, 0);
        Point p2 = new Point(100, 100);
        System.out.println("p1: " + p1.x + "|" + p1.y); // p1: 0|0
        System.out.println("p2: " + p2.x + "|" + p2.y); // p2: 100|100
        pseudoSwap(p1, p2);
        System.out.println("nach Methodendurchlauf:");
        System.out.println("p1: " + p1.x + "|" + p1.y); // p1: 0|0
        System.out.println("p2: " + p2.x + "|" + p2.y); // p2: 100|100
    }
    
    private static void pseudoSwap(Point pp1, Point pp2){
        Point temp = pp1;
        pp1 = pp2;
        pp2 = temp;
        System.out.println("innerhalb pseudoSwap():");
        System.out.println("p1: " + pp1.x + "|" + pp1.y); // p1: 100|100
        System.out.println("p2: " + pp2.x + "|" + pp2.y); // p2: 0|0
    }
}

Nun sollte auch der dritte Fall einleuchten. In ihm werden Membervariablen eines übergebenen Referenztyps dauerhaft geändert.

import java.awt.Point;

public class Call_by_Value3 {

    public static void main(String[] args) {
        Point p1 = new Point(0, 0);
        Point p2 = new Point(100, 100);
        System.out.println("p1: " + p1.x + "|" + p1.y);    // p1: 0|0
        System.out.println("p2: " + p2.x + "|" + p2.y);    // p2: 100|100
        changePointValue(p1, p2);
        System.out.println("nach Methodendurchlauf:");
        System.out.println("p1: " + p1.x + "|" + p1.y);    // p1: 50|50
        System.out.println("p2: " + p2.x + "|" + p2.y);    // p2: 100|100
    }
    
    private static void changePointValue(Point pp1, Point pp2){
        System.out.println("Innerhalb changePointValue()");
        pp1.x = 50;
        pp1.y = 50;
        System.out.println("nach Wertezuweisung:");
        System.out.println("pp1: " + pp1.x + "|" + pp1.y);    // p1: 50|50
        System.out.println("pp2: " + pp2.x + "|" + pp2.y);    // p2: 100|100
        Point temp = pp1;
        pp1 = pp2;
        pp2 = temp;
        System.out.println("nach Referenztausch:");            
        System.out.println("pp1: " + pp1.x + "|" + pp1.y);    // p1: 100|100
        System.out.println("pp2: " + pp2.x + "|" + pp2.y);    // p2: 50|50
    }
}

Das Ergebnis verwirrt zunächst, klärt sich jedoch bei genauerer Betrachtung, wenn man beachtet, dass innerhalb von changePointValue() zunächst die Werte geändert werden, auf die die als Parameter übergebene Referenz zeigt. Dies ist ja eine Kopie der Ausgangsreferenz, die ja auf das eigentliche Objekt zeigt. Es besitzt somit jetzt zwei Zeiger, die das selbe Objekt betreffen. Ändert man jetzt dessen Eigenschaften, ist dies natürlich dauerhaft.
Nach dem Tausch der Objektreferenzen zeigen sich dann selbstverständlich auch deren Eigenschaften als ausgetauscht (weil ja die Verweise getauscht wurden). Das ist jedoch über den Lebenszyklus der Methode hinaus nicht dauerhaft, weil innerhalb der Methode wiederum nur mit Kopien der Referenzen gearbeitet wurde.