First off: You're absolutely correct, Java is purely pass-by-value.
The key thing to remember is that when we have a variable like location
that refers to an array or object, the variable doesn't actually contain the array or object, it contains a reference to the array or object elsewhere in memory. This is the big difference between arrays/objects and primitives. Consider this code:
int primitive = 5;
int[] ref = new int[2];
That gives us this in memory:
+-----------+
| primitive |
+-----------+
| 5 |
+-----------+
+-----------+
| ref |
+-----------+ +--------+
| reference |----->| int[2] |
+-----------+ +--------+
| 0 |
| 0 |
+--------+
Note the difference. So what is "reference" in the above? It's a value, like 123456789, that the VM uses to locate the array in memory. We can't know the value, and we don't care about it. All we care about is that the VM knows how to interpret it.
So the code you quoted can modify the array because the value passed into the function is a copy of the reference to the array, not a copy of the array. Using that reference to modify the array modifies that one copy of the array, and so you can see those modifications regardless of which copy of the reference you're using to look.
After this line:
int[] location = new int[2];
...we have this in memory:
+-----------+
| location |
+-----------+ +--------+
| reference |------>| int[2] |
+-----------+ +--------+
| 0 |
| 0 |
+--------+
Then, when you do this:
view.getLocationInWindow(location);
within getLocationInWindow
, it receives a copy of the reference (because Java is pass-by-value), so say getLocationInWindow
's argument name is foo
, during the call we have this:
+-----------+
| location |
+-----------+ +--------+
| reference |---+-->| int[2] |
+-----------+ | +--------+
| | 0 |
| | 0 |
+-----------+ | +--------+
| foo | |
+-----------+ |
| reference |---+
+-----------+
Accessing the array, through either copy of the reference, accesses the same array. (And again, this is also true for object references.)