242

Arrays are not a primitive type in Java, but they are not objects either, so are they passed by value or by reference? Does it depend on what the array contains, for example references or a primitive type?

xDan
  • 19
  • 3
Froskoy
  • 2,967
  • 5
  • 20
  • 21
  • 18
    Arrays are Objects, yes, but nothing in Java is passed by reference. All parameter passing is by value. In the case of an Object, what gets passed is a reference to the Object (i.e. a pointer), by value. Passing a reference by value is not the same as pass by reference. – aroth Oct 06 '12 at 07:46
  • You may find this useful: http://stackoverflow.com/a/9404727/597657 – Eng.Fouad Oct 06 '12 at 08:24
  • I cannot add an answer to this question, but I wrote a code snippet that might be helpful for understanding the answers below: https://write.as/1wjcm7m50w41k.md. – myx Mar 18 '19 at 05:05
  • Java does not consider references, other languages do – Sam Ginrich May 21 '23 at 11:57

7 Answers7

311

Everything in Java is passed by value. In case of an array (which is nothing but an Object), the array reference is passed by value (just like an object reference is passed by value).

When you pass an array to other method, actually the reference to that array is copied.

  • Any changes in the content of array through that reference will affect the original array.
  • But changing the reference to point to a new array will not change the existing reference in original method.

See this post: Is Java "pass-by-reference" or "pass-by-value"?

See this working example:

public static void changeContent(int[] arr) {

   // If we change the content of arr.
   arr[0] = 10;  // Will change the content of array in main()
}

public static void changeRef(int[] arr) {
   // If we change the reference
   arr = new int[2];  // Will not change the array in main()
   arr[0] = 15;
}

public static void main(String[] args) {
    int [] arr = new int[2];
    arr[0] = 4;
    arr[1] = 5;

    changeContent(arr);

    System.out.println(arr[0]);  // Will print 10.. 
  
    changeRef(arr);

    System.out.println(arr[0]);  // Will still print 10.. 
                                 // Change the reference doesn't reflect change here..
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
174

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.

Related SO question:

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • 1
    That isn't a citation. Sorry, but I don't think there is any point in continuing this discussion. I am simply not interested in the "Java is pass by reference" debate. If you want to write your own answer to this question, feel free. But I am going to request the mods to delete these comments on this answer as "no longer needed". – Stephen C Dec 03 '22 at 12:47
65

Arrays are in fact objects, so a reference is passed (the reference itself is passed by value, confused yet?). Quick example:

// assuming you allocated the list
public void addItem(Integer[] list, int item) {
    list[1] = item;
}

You will see the changes to the list from the calling code. However you can't change the reference itself, since it's passed by value:

// assuming you allocated the list
public void changeArray(Integer[] list) {
    list = null;
}

If you pass a non-null list, it won't be null by the time the method returns.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • No, everything is passed by value in Java ! Passing by reference doesn't exist in JAva, as it doesn't exist in ANSI C, thats why pointers exist ... – aleroot Oct 06 '12 at 07:53
  • 2
    @aleroot: I said a reference is passed to the method, otherwise you couldn't see changes, not that java is pass-by-reference! Yes, the reference is passed by values, but that's not the point. – Tudor Oct 06 '12 at 07:53
  • 2
    @Tudor your sentence is not clear ... – aleroot Oct 06 '12 at 07:54
  • @aleroot: Ok, I've added some more comments... – Tudor Oct 06 '12 at 07:56
  • 2
    *"However you can't change the reference itself, since it's passed by value"* - Actually, you can (locally) change the reference. What you cannot change is *the variable from whence the reference was fetched in the calling context*. This is only confusing if people conflate the reference and the variable that holds the reference. – Stephen C Oct 29 '16 at 04:25
13

No that is wrong. Arrays are special objects in Java. So it is like passing other objects where you pass the value of the reference, but not the reference itself. Meaning, changing the reference of an array in the called routine will not be reflected in the calling routine.

sakthisundar
  • 3,278
  • 3
  • 16
  • 29
  • Thanks. So does every array access have to be dereferenced? Does this mean that using arrays is just as slow as using any other type of list in Java, except you can store primitive types in them, which do not need to be dereferenced? – Froskoy Oct 06 '12 at 08:11
  • No, because the storage is contiguous in the data in the heap, which means that iterated lookup is much cheaper in terms of CPU time. A List does not guarantee contiguous storage. – noisesmith Dec 10 '13 at 18:34
  • *"So it is like passing other objects where you pass the value of the reference, but not the reference itself."* This is misleading / wrong in two respects. 1) Arrays are not "special objects" in this respect. They behave exactly the same as non-array objects with respect to parameter passing semantics. 2) The "value of the reference" and "the reference" are the same thing. What you *should* be saying is that you are passing the value of the reference not the value of object that the reference points to. – Stephen C Aug 23 '19 at 02:50
  • Arrays are faster but not because "A List does not guarantee contiguous storage" -- they are faster because their API shape, memory, access, and implementation are built straight into the language (not dynamic). The Java spec has defined how they are stored and defined the ways to access them. Access does not involve the overhead of calling methods like `#get`, `#set` `#iterator`, `#size`, etc. You could theoretically implement int[] as an Object, use a contiguous chunk of memory, etc., and write a compiler to use it instead of native arrays. It would still be far slower than native arrays. – AndrewF Dec 25 '19 at 00:15
5

The definitive discussion of arrays is at http://docs.oracle.com/javase/specs/jls/se5.0/html/arrays.html#27803 . This makes clear that Java arrays are objects. The class of these objects is defined in 10.8.

Section 8.4.1 of the language spec, http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#40420 , describe how arguments are passed to methods. Since Java syntax is derived from C and C++, the behavior is similar. Primitive types are passed by value, as with C. When an object is passed, an object reference (pointer) is passed by value, mirroring the C syntax of passing a pointer by value. See 4.3.1, http://docs.oracle.com/javase/specs/jls/se5.0/html/typesValues.html#4.3 ,

In practical terms, this means that modifying the contents of an array within a method is reflected in the array object in the calling scope, but reassigning a new value to the reference within the method has no effect on the reference in the calling scope, which is exactly the behavior you would expect of a pointer to a struct in C or an object in C++.

At least part of the confusion in terminology stems from the history of high level languages prior to the common use of C. In prior, popular, high level languages, directly referencing memory by address was something to be avoided to the extent possible, and it was considered the job of the language to provide a layer of abstraction. This made it necessary for the language to explicitly support a mechanism for returning values from subroutines (not necessarily functions). This mechanism is what is formally meant when referring to 'pass by reference'.

When C was introduced, it came with a stripped down notion of procedure calling, where all arguments are input-only, and the only value returned to the caller is a function result. However, the purpose of passing references could be achieved through the explicit and broad use of pointers. Since it serves the same purpose, the practice of passing a pointer as a reference to a value is often colloquially referred to a passing by reference. If the semantics of a routine call for a parameter to be passed by reference, the syntax of C requires the programmer to explicitly pass a pointer. Passing a pointer by value is the design pattern for implementing pass by reference semantics in C.

Since it can often seem like the sole purpose of raw pointers in C is to create crashing bugs, subsequent developments, especially Java, have sought to return to safer means to pass parameters. However, the dominance of C made it incumbent on the developers to mimic the familiar style of C coding. The result is references that are passed similarly to pointers, but are implemented with more protections to make them safer. An alternative would have been the rich syntax of a language like Ada, but this would have presented the appearance of an unwelcome learning curve, and lessened the likely adoption of Java.

In short, the design of parameter passing for objects, including arrays, in Java,is esentially to serve the semantic intent of pass by reference, but is imlemented with the syntax of passing a reference by value.

Steven McGrath
  • 1,717
  • 11
  • 20
  • 1
    "Since Java syntax is derived from C and C++, the behavior is similar." - Twaddle! Similar syntax does not imply similar semantics. – Stephen C Oct 06 '12 at 09:18
  • I referenced the older spec because it is still correct, and I don't know which version the OP is using. Parameter passing is described in 8.4.1 as follows: **When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables, each of the declared Type, before execution of the body of the method or constructor. The Identifier that appears in the DeclaratorId may be used as a simple name in the body of the method or constructor to refer to the formal parameter.** – Steven McGrath Oct 06 '12 at 09:40
  • Regarding sytax, the parallel between Java, C, and C++ is far from accidental, and the design was intended to ease the transition for C and C++ programmers. Language design is a matter of human communications, not mathematical rigor, and mixing familiar syntax with unfamiliar semantics would have created undue complexity. We were striving for a system that would be easy to adopt. – Steven McGrath Oct 06 '12 at 09:50
  • You miss my point. I'm sure you know of cases where two related languages have identical syntaxes but the semantics is different. The point I am making that same syntax DOES NOT imply same semantics, whether the languages are related or not. – Stephen C Oct 06 '12 at 11:38
  • Also, talking about the "semantic intent of pass by reference" is making assumptions about that intent that are at odds with 50% of the use cases of pass by reference in FORTRAN, C, C++ etcetera. For example the `swap(int &a, int &b)` method. And bear in mind that call-by-reference in classic FORTRAN did not involve pointers and their risks. (You could even argue that C doesn't do call by reference at all. What is it is doing is explicitly creating passing pointers ... by value ... that have to be used in certain ways to avoid "unspecified behaviour".) – Stephen C Oct 06 '12 at 11:49
  • @Stephen C, Actually, I'm hard pressed to think of an example where similar syntax was not reflective of an attempt to achieve similar semantics. Could you provide an example? – Steven McGrath Oct 06 '12 at 11:52
  • Here is an obvious one. FORTRAN and Algol 60 and C use identical syntax for a method / function / procedure call. `name(expr, expr, expr)`. But the argument passing semantics are different in each case. Another obvious example `if (a = 1)` in C versus Java. Now this is a GOOD difference ... but it demonstrates the point I was trying to make more clearly due to the closer relationship between the languages. – Stephen C Oct 06 '12 at 11:59
  • A third example is the rather different meaning of `static` in C versus Java. – Stephen C Oct 06 '12 at 12:01
  • I think were actually saying the same thing about Fortran vs. C. Fortran's use of call by reference was essential to not exposing raw pointers (although it did render dynamic memory allocation impractical). The original C compiler was designed to be extremely lightweight, so the language does not implement call by reference, and pointers fill in the gap. The use case you mention is also reflective of the low-level nature of C, as such a routine in Fortran would likely have entailed inline assembly. This is not the most common use case for application developers in my experience. – Steven McGrath Oct 06 '12 at 12:02
  • I see where you're coming from on Fortan, Algol and C, but the syntaxes of those languages are not nearly as slavishly similar as Java and C++. Perhaps I'm a little to close to the history to not see this as apparent. – Steven McGrath Oct 06 '12 at 12:06
  • I can trivially implement `swap` on scalar variables in classic FORTRAN IV ... unless I've misremembered it. – Stephen C Oct 06 '12 at 12:06
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/17644/discussion-between-steven-mcgrath-and-stephen-c) – Steven McGrath Oct 06 '12 at 12:07
4

Everything in Java is passed by value .

In the case of the array the reference is copied into a new reference, but remember that everything in Java is passed by value .

Take a look at this interesting article for further information ...

aleroot
  • 71,077
  • 30
  • 176
  • 213
1

Kind of a trick realty... Even references are passed by value in Java, hence a change to the reference itself being scoped at the called function level. The compiler and/or JVM will often turn a value type into a reference.

Jeff Watkins
  • 6,343
  • 16
  • 19
  • Think it was Kernighan & Ritchie who felt like calling a pointer a value. Inside the inheritance of this thinking, Java is Reference Oriented, rather than Object Oriented, which is the key to ´understanding´. – Sam Ginrich Apr 05 '22 at 17:54