Are Arrays Passed by Value or Passed by Reference in Java

Are arrays passed by value or passed by reference in Java?

Your question is based on a false premise.

Arrays are not a primitive type in Java, but they are not objects either ... "

In fact, all arrays in Java are objects1. Every Java array type has java.lang.Object as its supertype, and inherits the implementation of all methods in the Object API.

... so are they passed by value or by reference? Does it depend on what the array contains, for example references or a primitive type?

Short answers: 1) pass by value, and 2) it makes no difference.

Longer answer:

Like all Java objects, arrays are passed by value ... but the value is the reference to the array. So, when you assign something to a cell of the array in the called method, you will be assigning to the same array object that the caller sees.

This is NOT pass-by-reference. Real pass-by-reference involves passing the address of a variable. With real pass-by-reference, the called method can assign to its local variable, and this causes the variable in the caller to be updated.

But not in Java. In Java, the called method can update the contents of the array, and it can update its copy of the array reference, but it can't update the variable in the caller that holds the caller's array reference. Hence ... what Java is providing is NOT pass-by-reference.

Here are some links that explain the difference between pass-by-reference and pass-by-value. If you don't understand my explanations above, or if you feel inclined to disagree with the terminology, you should read them.

  • http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/topic/com.ibm.xlcpp8a.doc/language/ref/cplr233.htm
  • http://www.cs.fsu.edu/~myers/c++/notes/references.html

Related SO question:

  • Is Java "pass-by-reference" or "pass-by-value"?

Historical background:

The phrase "pass-by-reference" was originally "call-by-reference", and it was used to distinguish the argument passing semantics of FORTRAN (call-by-reference) from those of ALGOL-60 (call-by-value and call-by-name).

  • In call-by-value, the argument expression is evaluated to a value, and that value is copied to the called method.

  • In call-by-reference, the argument expression is partially evaluated to an "lvalue" (i.e. the address of a variable or array element) that is passed to the calling method. The calling method can then directly read and update the variable / element.

  • In call-by-name, the actual argument expression is passed to the calling method (!!) which can evaluate it multiple times (!!!). This was complicated to implement, and could be used (abused) to write code that was very difficult to understand. Call-by-name was only ever used in Algol-60 (thankfully!).

UPDATE

Actually, Algol-60's call-by-name is similar to passing lambda expressions as parameters. The wrinkle is that these not-exactly-lambda-expressions (they were referred to as "thunks" at the implementation level) can indirectly modify the state of variables that are in scope in the calling procedure / function. That is part of what made them so hard to understand. (See the Wikipedia page on Jensen's Device for example.)


1. Nothing in the linked Q&A (Arrays in Java and how they are stored in memory) either states or implies that arrays are not objects.

Can we use pass by reference in java? If No How does java.util.Arrays.sort works?

Arrays are reference types, so the iArr variable holds a reference to an array.

In other words, when you call

Arrays.sort(iArr);

you're passing a reference (by value) to the sort method, which sorts the array that iArr refers to.


From comments:

What does passing a reference (by value) actually mean?

What pass by reference means is that you're basically passing the variable itself to the method. I.e., what ever the method does with the variable affects the variable on the outside. This is never the case in Java. (Try implementing a swap method and you'll see what I mean.) Passing by value means that you pass the value that's stored in the variable. In this case the value is a reference, so it's passing a reference by value.


Re. second update:

Judging from your image, I think you've understood the situation very well, and I think it boils down to terminology.

If we forget about C++ for a while, it's really simple. All you need to keep in mind is that (A) when you invoke method(var) the argument is a copy of whatever var contains, and (B) the content of a non-primitive variable is a reference (a "pointer" if you so like).

Note that in your question you have

int iArr[] = {2, 1, 9, 6, 4};

which is equivalent to

int[] iArr = new int[] { 2, 1, 9, 6, 4 };

so it all checks out: iArr holds a reference and new returns a reference.

When you invoke Arrays.sort(iArr) the content of iArr is passed (i.e. the reference to the array). This is still not pass-by-reference because the value is passed, not the variable itself. If you reassign the formal parameter inside the method to point to some other array, iArr will still point to the original array when the method returns.

If we do think in terms of C++ things tend to be a bit more complicated; C++ notion of reference is slightly different. With a C++ reference you can in fact implement a real swap:

void swap(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}

I.e. you can pass in "a variable" (as opposed to just the content of a variable). I like to think of this as you're sharing the scope of the variable with the method you're calling. This can't be done in Java.

So with that in mind, I'd say Java reference are much more like C++ pointers, except that they are limited in the sense that you can't dereference using * operator as you can in C++ (you can't do *person in Java, even though person stores what corresponds to a pointer to a person) and you can't get the address of an object using & operator. Also you can't do any pointer arithmetic. You can't for instance do iArr + 3 to get to the fourth element of your array.

Array are passed by value or by reference?

There's a crucial point to make here, everything is really passed by value for example, this will pass a copy of a to foo() (which happens to be a pointer to some memory):

int *a = malloc(20);
foo(a);

That's why if you do something like this in foo() it doesn't really change the pointer a in main() but changes the local copy:

foo(int *a)
{
a = NULL; /*changes local copy of the pointer*/
}

In other words, you can use foo()'s local copy of a to change the memory pointed to by 'a' but not to change what a points to in main().

Now, to pass something "by reference" you pass a copy of a pointer-to-pointer to the function (something like a->b->memory):

int *a = malloc(20);
foo(&a);

So when you assign to it in foo() to changes the pointer in main():

foo(int **a)
{
*a = NULL; /*changes the pointer in main */
}

Now to answer some of your other questions, when you use an array name it is converted to a pointer to the first element of the array:

int *a = malloc(20);
int b[] = {1,2,3,4,5};
foo(a);
foo(b);

The last two function calls are equivalent in that they both pass a pointer to the first element of some memory, the difference is the memory for a is allocated on the heap, the memory of b however, is allocated on the stack.

Finally, strings, the following are similar, in that the same principle applies, however the first one is a constant string literal and should be defined as const and you should not attempt to modify it anywhere but you can change the second one:

const char *c1 = "string";
char c2 [] = "string";

 

Are arrays in java pass by reference or pass by value?

Everything in Java is pass-by-value. However, if you're passing a reference, it's the value of the reference.

Since Java methods can't reach into the caller's stack to reassign variables, no method call can change the identity of a reference (address) there. This is what we mean when we say Java is not pass-by-reference. This contrasts with C++ (and similar languages), which allows this in some cases.

Now let's look at some effects.

If I do:

Object[] o = ...
mutateArray(o);

the contents can be different afterwards, since all mutateArray needs is the address of an array to change its contents. However, the address of o will be the same. If I do:

String x = "foo";
tryToMutateString(x);

the address of x is again the same afterwards. Since strings are immutable, this implies that it will also still be "foo".

To mutate an object is to change the contents of it (e.g. successfully changing the last element of o, or trying to change the last letter of "foo" to 'd'). This should not be be confused with reassigning x or o in the caller's stack (impossible).

The Wikipedia section on call by sharing may shed additional light.



Related Topics



Leave a reply



Submit