Is Java Pass-by-Value or Pass-by-Reference?
Introduction
"Is Java pass-by-value or pass-by-reference?" is one of the most frequently asked - and most frequently mis-answered - Java questions. The short answer is: Java is always pass-by-value. But when the value being passed is a reference to an object, the results can look like pass-by-reference, which is where the confusion comes from. This tutorial settles the question with examples. We will start by defining the two terms. We will then pass primitives to a method, and then object references. Next we will run the experiment that proves Java is not pass-by-reference - the swap test. Lastly, we will look at how immutable objects such as
(Note - This tutorial builds on Java MethodsClick to read tutorial: Java Methods: Defining, Calling and Returning Values, and on the idea that array and object variables hold references, from Java ArraysClick to read tutorial: Java Arrays Tutorial: Declare, Create and Initialize.) Pass-by-value vs pass-by-reference
OUTPUT of the above code
The parameter
Passing object references
When an object is passed, the parameter receives a copy of the reference. The caller's variable and the parameter now point to the same object, so the method can change that object's contents, and the caller will see the change.
OUTPUT of the above code
This is why many people think Java passes objects by reference. But look closely: the method changed the object the reference points to. It did not change the caller's variable. The next experiment shows the difference.
The swap test - proof that Java is pass-by-value
With real pass-by-reference, a method could swap two of the caller's variables. In Java, it cannot - and the same is true of reassigning a parameter to a new object.
OUTPUT of the above code
Explanation of the code
What about String and other immutable objects?
A
OUTPUT of the above code
To change a string - or any immutable value - in the caller, return the new value and assign it there, as
String fit in, and what this means for the methods you write.(Note - This tutorial builds on Java MethodsClick to read tutorial: Java Methods: Defining, Calling and Returning Values, and on the idea that array and object variables hold references, from Java ArraysClick to read tutorial: Java Arrays Tutorial: Declare, Create and Initialize.) Pass-by-value vs pass-by-reference
- Pass-by-value: the method receives a copy of the argument's value in its parameter. Assigning a new value to the parameter has no effect on the caller's variable.
- Pass-by-reference: the parameter becomes an alias for the caller's variable itself. Assigning to the parameter changes the caller's variable. (C++ reference parameters and C#
refparameters work this way.)
- for a primitive variable, the value is the number, character or boolean itself;
- for an object variable (including arrays and strings), the value is a reference - something like the object's address. The object itself is never copied.
Passing a primitive to a method
//PassPrimitive.java
public class PassPrimitive {
static void addBonus(int score) {
score = score + 10;
System.out.println(" inside addBonus: score = " + score);
}
public static void main(String[] args) {
int score = 70;
addBonus(score);
System.out.println("after addBonus: score = " + score);
}
}
inside addBonus: score = 80 after addBonus: score = 70
score received a copy of 70. Changing the copy to 80 did not affect the caller's score - even though the two variables have the same name, they are different variables in different stack frames. To get the new value back, the method must return it: score = addBonus(score);.
Passing an array and an object to a method
//PassReference.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PassReference {
static void doubleAll(int[] values) {
for (int i = 0; i < values.length; i++) {
values[i] *= 2; // changes the shared array
}
}
static void addGuest(List<String> guests) {
guests.add("Nancy"); // changes the shared list
}
public static void main(String[] args) {
int[] prices = {10, 20, 30};
doubleAll(prices);
System.out.println("prices after doubleAll: " + Arrays.toString(prices));
List<String> guests = new ArrayList<>(List.of("Tom", "Harry"));
addGuest(guests);
System.out.println("guests after addGuest : " + guests);
}
}
prices after doubleAll: [20, 40, 60] guests after addGuest : [Tom, Harry, Nancy]
Swapping and reassigning reference parameters
//SwapTest.java
import java.util.ArrayList;
import java.util.List;
public class SwapTest {
static void swap(StringBuilder a, StringBuilder b) {
StringBuilder temp = a;
a = b;
b = temp;
System.out.println(" inside swap: a = " + a + ", b = " + b);
}
static void replaceList(List<String> list) {
list = new ArrayList<>(); // the parameter now points to a NEW list
list.add("Ethan");
System.out.println(" inside replaceList: " + list);
}
public static void main(String[] args) {
StringBuilder first = new StringBuilder("first");
StringBuilder second = new StringBuilder("second");
swap(first, second);
System.out.println("after swap: first = " + first + ", second = " + second);
List<String> names = new ArrayList<>(List.of("Tom"));
replaceList(names);
System.out.println("after replaceList: " + names);
}
}
inside swap: a = second, b = first after swap: first = first, second = second inside replaceList: [Ethan] after replaceList: [Tom]
- Inside
swap(), the parametersaandbwere swapped - but they are only copies of the references. The caller'sfirstandsecondstill point to the same objects as before. replaceList()pointed its parameter at a brand-new list. The caller'snamesstill points to the original list, which was never touched.- If Java were pass-by-reference, both changes would have been visible to the caller. They were not, which proves that Java passes references by value.
String is passed like any object - as a copy of its reference. But strings are immutableClick to read tutorial: Java String Basics and Why Strings Are Immutable, so there is no method which can change the shared object. Anything that looks like a change creates a new String, and assigning it to the parameter only changes the parameter. The same is true for the wrapper classes, such as Integer.
Passing a String to a method
//PassString.java
public class PassString {
static void shout(String message) {
message = message.toUpperCase() + "!";
System.out.println(" inside shout: " + message);
}
static String shoutAndReturn(String message) {
return message.toUpperCase() + "!";
}
public static void main(String[] args) {
String message = "hello";
shout(message);
System.out.println("after shout: " + message);
message = shoutAndReturn(message);
System.out.println("after shoutAndReturn: " + message);
}
}
inside shout: HELLO! after shout: hello after shoutAndReturn: HELLO!
shoutAndReturn() does.
What this means for your methods
- Return new values for primitives and immutable objects. A method cannot change the caller's variables.
- Be careful when changing objects you are given. Changes to a passed array or list affect the caller, which can surprise them. Document it if a method does this, or work on a copy instead.
- Make parameters final if it helps. Declaring a parameter
finalprevents accidentally reassigning it, which, as we saw, never affects the caller anyway.
String behave, and what this means for the methods you write. Java is always pass-by-value. In the next tutorial, we will define several methods with the same name using method overloadingClick to read tutorial: Method Overloading in Java with Examples.Java Fundamentals Tutorials
Java Methods: Defining, Calling and Returning ValuesClick to read tutorial: Java Methods: Defining, Calling and Returning Values Method Overloading in Java with ExamplesClick to read tutorial: Method Overloading in Java with Examples Java Varargs: Variable-Length Arguments with ExamplesClick to read tutorial: Java Varargs: Variable-Length Arguments with Examples Recursion in Java with ExamplesClick to read tutorial: Recursion in Java with Examples Static vs Instance Methods in JavaClick to read tutorial: Static vs Instance Methods in Java What is Java? History, Features, Editions and UsesClick to read tutorial: What is Java? History, Features, Editions and Uses
Java Methods: Defining, Calling and Returning ValuesClick to read tutorial: Java Methods: Defining, Calling and Returning Values Method Overloading in Java with ExamplesClick to read tutorial: Method Overloading in Java with Examples Java Varargs: Variable-Length Arguments with ExamplesClick to read tutorial: Java Varargs: Variable-Length Arguments with Examples Recursion in Java with ExamplesClick to read tutorial: Recursion in Java with Examples Static vs Instance Methods in JavaClick to read tutorial: Static vs Instance Methods in Java What is Java? History, Features, Editions and UsesClick to read tutorial: What is Java? History, Features, Editions and Uses