Pass by Value
Java always passes arguments by value.
It’s simple in the case of primitives, a copy of the value is assigned to the function argument:
private void doSomething(int a) {
a = a + 1;
out.println(a);
}
private void myFunction() {
int x = 5;
doSomething(x);
out.println(x);
}
As expected, this outputs:
6
5
The value of the x variable (5) is passed to the doSomething method and copied to an argument named a. This local argument is incremented by 1 and output. The result is 6.
When the function returns, we output the original x variable. Its value is still 5.
Similarly, when passing an object, a copy of the reference to the object is passed to the function:
private void doSomething(Car car) {
car.setMake("BMW");
car.setModel("SUV X1");
car = new Car("Ford", "Exporer");
out.println(car.getMake() + " " + car.getModel());
}
private void myFunction() {
var c = new Car("Mazda", "323");
doSomething(c);
out.println(c.getMake() + " " + c.getModel());
}
This outputs:
Ford Explorer
BMW SUV X1
In myFunction we have a variable named c which refers to a Car object in memory initialized to Mazda 323. We call c a reference because it is not the object, it points to the object. Its value is a reference to the object.
When the c variable is passed to the doSomething method, a copy of its value is passed – its value being a reference to the Car object.
The car argument of the doSomething method now points to the same Car object – Mazda 323.
Because the argument points to the same object, changes are applied directly to the object. So our Car object is now a BMW SUV X1.
Next. we change the car argument to refer to a newly created object (Ford Explorer). This change only affects the value of the car argument, the value of our c variable is untouched.
Lastly, we exit the function and our c variable is still pointing to the Car object it had created, the Mazda 323 which had been updated to a BMW SUV X1.
Pass by Reference
In languages like C#, it is possible to actually pass our original variable by reference (var), or a reference to an uninitialized variable (out). This is useful in some circumstances, and you’ll see idioms like:
public bool TryParse(String text, out int result) {
// ...
}
int x;
if (TryParse("123", out x)) { ... }
This function will try convert the string to an integer, if successful the referenced variable result is initialized with the integer value and true is returned. On failure, false is returned. With modern C# this idiom is even more concise.
Not to worry, in Java we can achieve a similar idiom using Optional:
public Optional<Integer> TryParse(String text) {
// try convert and set result
return success ? Optional.of(result) : Optional.empty();
}
int x = TryParse("123");
if (x.isPresent()) { .... }
Remember, Java always passes by value.