Java DISCUSSION

Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

Started by hind Java pass by valueobject referencesmethod parametersimmutabilitydefensive copy
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

hind Java Forum
#1

I have four helper methods. void inc(int n) { n++; } has no effect on the caller's variable. void add(List<Integer> list) { list.add(5); } does change the caller's list. But void reset(List<Integer> list) { list = new ArrayList<>(); } leaves the caller's list untouched, and void shout(String s) { s = s.toUpperCase(); } does nothing either.

My textbook says primitives are passed by value and objects by reference, but that does not explain the third and fourth cases. What is the actual rule, and how do I write a method that gives back more than one result?

Community replies 5

Re: Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

#2

Java is always pass-by-value. What differs is what the value is. For a primitive, the variable holds the number and the method receives a copy of it. For an object type, the variable holds a reference to an object on the heap, and the method receives a copy of that reference. Caller and callee have two separate variables pointing at one object.

list.add(5) follows the copied reference to the shared object and modifies it, which the caller sees. list = new ArrayList<>() overwrites the method's own copy of the reference; the caller's variable still points at the original list. For C programmers: it is like passing a pointer by value. You can change what it points to, but assigning to the pointer itself changes only the local copy.

Re: Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

#3

The String case is the same rule plus immutability. s.toUpperCase() cannot modify the original String; no method can. It creates a new one, and s = ... rebinds only the local parameter. Wrapper types behave the same way: void inc(Integer n) { n++; } unboxes, adds one, boxes a new Integer and assigns it to the local n.

The test for real pass-by-reference is whether you can write a swap(a, b) that exchanges the caller's two variables. With reference parameters in C++ or ref in C# you can. In Java you cannot, for primitives or for objects.

Re: Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

#4

To get a result out of a method, return it: s = shout(s); with String shout(String s) { return s.toUpperCase(); }. For several results return a small object. Since Java 16 a record makes that a one-liner: record MinMax(double min, double max) {} and return new MinMax(lo, hi);.

Avoid the old trick of passing a one-element array, int[] out = new int[1], just to simulate an output parameter. It works, because an array is an object reached through the copied reference, but it hides the data flow. Mutating a collection that was passed in is acceptable when that is the documented purpose of the method, as in a fill(list).

Re: Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

#5

The flip side deserves attention: because references are copied rather than objects, handing out an internal collection shares it. List<Integer> getSamples() { return samples; } lets any caller clear() your private list, and a constructor that stores this.samples = samples; keeps a list that the caller can still modify later.

The defensive options are to copy on the way in, this.samples = new ArrayList<>(samples); or List.copyOf(samples) (Java 10 and later, an unmodifiable copy), and to return Collections.unmodifiableList(samples), which is a read-only view. final does not help here: a final field or parameter only prevents reassignment of the reference, and the object behind it stays mutable.

Re: Is Java pass-by-value or pass-by-reference? My method changes a list but not an int or String

#6

Arrays are objects too, so void zero(int[] a) { a[0] = 0; } changes the caller's array, while a = new int[4]; inside the method does not.

You can watch this in a debugger, or print System.identityHashCode(list) inside and outside the method: the numbers match until the method reassigns its parameter. On cost, passing an object of any size copies only the reference, a few bytes, so there is no performance reason to avoid passing large arrays or collections to methods. And because variables hold references, == between two object variables asks whether they are the same object; comparing contents is the job of equals().

TEP COMMUNITY