3 Comments
User's avatar
Owen O'Malley's avatar

This article is very misleading. Java is pass by value for primitives, which includes references, and pass by reference for objects.

I would argue that changeAgeAndPerson should have been a compile time error, because it almost certainly isn’t what the programmer desired. Of course programmers who need to create a new object, usually explicitly return it from the function.

Expand full comment
Thiago Bomfim's avatar

Thanks for the comment!

This is a common misconception, but Java really is pass-by-value across the board.

What often confuses people is that, for objects, the value being passed is actually the reference.

This means methods receive a copy of the reference, they can use it to modify the object’s fields, but they can’t make the caller’s variable point to a different object.

That’s why changeAge works (it changes the object), but changeAgeAndPerson doesn’t (it just reassigns the local copy of the reference).

If Java were truly pass-by-reference, reassigning inside the method would affect the caller’s variable too, but it doesn’t.

If you want an official detail about it, you can find it here:

If you want an official explanation, you can find it here:

https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

“Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.”

Hope that clears things up!

Expand full comment
Owen O'Malley's avatar

I understand what you are saying, but it doesn't match how users think about it. Yes, "changeAge(p)" passes a reference, but there is no way to *not* pass a reference in Java. Therefore, from the user's point of view Java has passed p by reference. Furthermore, if p was passed by value changeAge wouldn't change the parameter either.

I stand by my earlier comment that Java allowing the user to change the value of parameters was an error-prone design and should not have been allowed.

Most other programming languages make this much clearer by making the references explicit. In C++, you have to use changePerson(&p) to pass p by reference. Rust makes it even clearer by requiring changePerson(&mut p) saying that you can mutate p inside the function. So no, from the user's point of view, Java only passes objects and arrays by reference.

If we wrap the person in an array, now everything is passed by reference and all of the changes propagate.

public static void main(String[] args) {

var p = new Person[]{new Person()};

p[0].age = 10;

changeAge(p);

System.out.println(p[0].age); //5

changeAgeAndPerson(p);

System.out.println(p[0].age); //2

}

private static void changeAge(Person[] p) {

p[0].age = 5;

}

private static void changeAgeAndPerson(Person[] p) {

p[0] = new Person();

p[0].age = 2;

}

Expand full comment