You might know that Java passes by value, but it helps to understand why. Here's what happens when you pass mutable and immutable object references in Java. Many programming languages allow passing objects by reference or by value. In Java, we can only pass object parameters by value. This imposes limits and also raises questions. For instance, if the parameter value is changed in the method, what happens to the value following method execution? You may also wonder how Java manages object values in the memory heap. This article helps you resolve these and other common questions about object references in Java. Passing object references in Java In this article you’ll learn the difference between passing by reference and passing by value in Java and how to pass Java object references: ‘Pass by reference’ and ‘pass by value’ defined Java object references are passed by value Passing primitive types in Java Passing immutable object references in Java Passing mutable object references in Java What to avoid when passing object references What to remember about passing object references ‘Pass by reference’ and ‘pass by value’ defined Pass by reference means we pass the location in memory where the variable’s value is stored and pass by value means we pass a copy of the variable’s actual value. It’s a bit more complicated than that, of course, but this definition is a good starting point. Passing by value means we pass a copy of the value. Passing by reference means we pass the real reference to the variable in memory. Java object references are passed by value All object references in Java are passed by value. This means that a copy of the value will be passed to a method. The tricky part is that passing a copy of the value changes the real value of the object. This example should help you understand why: public class ObjectReferenceExample { public static void main(String... doYourBest) { Simpson simpson = new Simpson(); transformIntoHomer(simpson); System.out.println(simpson.name); } static void transformIntoHomer(Simpson simpson) { simpson.name = "Homer"; } } class Simpson { String name; } What do you think the simpson.name will be after the transformIntoHomer method is executed? In this case, it will be Homer! The reason is that Java object variables are simply references that point to real objects in the memory heap. Therefore, even though Java passes parameters to methods by value, if the variable points to an object reference, the real object will also be changed. If you’re still not sure how this works, consider the following diagram: Rafael Del Nero Passing primitive types in Java Like object types, primitive types are also passed by value. Can you guess what will happen to the primitive types in the following code example? public class PrimitiveByValueExample { public static void main(String... primitiveByValue) { int homerAge = 30; changeHomerAge(homerAge); System.out.println(homerAge); } static void changeHomerAge(int homerAge) { homerAge = 35; } } If you determined that the value would change to 30, you are correct. It’s 30 because (again) Java passes object parameters by value. The number 30 is just a copy of the value, not the real value. Primitive types are allocated in the stack memory, so only the local value will be changed. In this case, there is no object reference. Passing immutable object references in Java What if we did the same test with an immutable String object? Notice what happens when we change the value of a String: public class StringValueChange { public static void main(String... doYourBest) { String name = ""; changeToHomer(name); System.out.println(name); } static void changeToHomer(String name) { name = "Homer"; } } What do you think the output will be? If you guessed “” then congratulations! That happens because a String object is immutable, which means that the fields inside the String are final and can’t be changed. Making the String class immutable gives us better control over one of Java’s most used objects. If the value of a String could be changed, it would create many bugs. Note, also, that we are not changing an attribute of the String class; instead, we’re simply assigning a new String value to it. In this case, the “Homer” value will be passed to name in the changeToHomer method. The String “Homer” will be eligible to be garbage collected as soon as the changeToHomer method completes execution. Even though the object can’t be changed, the local variable will be. Passing mutable object references in Java Unlike String, most objects in the JDK are mutable, like the StringBuilder class. The example below is similar to the previous one, but features StringBuilder rather than String: static class MutableObjectReference { public static void main(String... mutableObjectExample) { StringBuilder name = new StringBuilder("Homer "); addSureName(name); System.out.println(name); } static void addSureName(StringBuilder name) { name.append("Simpson"); } } Can you guess the output for this example? In this case, because we’re working with a mutable object, the output will be “Homer Simpson.” You could expect the same behavior from any other mutable object in Java. Summary of what you’ve learned You’ve learned that Java objects are passed by value, meaning that a copy of the value is passed. Just remember that the copied value points to a real object in the Java memory heap. Also, remember that passing by value changes the value of the real object. What to avoid when passing Java object references Don’t try to change an immutable value by reference. Don’t try to change a primitive variable by reference. Don’t expect the real object won’t change when you change a mutable object parameter in a method (it will change). What to remember about passing Java object references Java always passes parameter variables by value. Object variables in Java always point to the real object in the memory heap. A mutable object’s value can be changed when it is passed to a method. An immutable object’s value cannot be changed, even if it is passed a new value. Test what you’ve learned about object references Now, let’s test what you’ve learned about object references. In the code example below, you see the immutable String and the mutable StringBuilder class. Each is being passed as a parameter to a method. Knowing that Java only passes by value, what do you believe will be the output once the main method from this class is executed? public class DragonWarriorReferenceChallenger { public static void main(String... doYourBest) { StringBuilder warriorProfession = new StringBuilder("Dragon "); String warriorWeapon = "Sword "; changeWarriorClass(warriorProfession, warriorWeapon); System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); } static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { warriorProfession.append("Knight"); weapon = "Dragon " + weapon; weapon = null; warriorProfession = null; } } Here are the options, check the end of the article for the answer. A: Warrior=null Weapon=null B: Warrior=Dragon Weapon=Dragon C: Warrior=Dragon Knight Weapon=Dragon Sword D: Warrior=Dragon Knight Weapon=Sword Solving the challenge The first parameter in the above example is the warriorProfession variable, which is a mutable object. The second parameter, weapon, is an immutable String: static void changeWarriorClass(StringBuilder warriorProfession, String weapon) { ... } At the first line of this method, we append the Knight value to the warriorProfession variable. Remember that warriorProfession is a mutable object; therefore the real object will be changed, and the value from it will be “Dragon Knight.” warriorProfession.append("Knight"); In the second instruction, the immutable local String variable will be changed to “Dragon Sword.” The real object will never be changed, however, since String is immutable and its attributes are final: weapon = "Dragon " + weapon; Finally, we pass null to the variables here, but not to the objects. The objects will remain the same as long as they are still accessible externally—in this case through the main method. And, although the local variables will be null, nothing will happen to the objects: weapon = null; warriorProfession = null; From this we can conclude that the final values from our mutable StringBuilder and immutable String will be: System.out.println("Warrior=" + warriorProfession + " Weapon=" + warriorWeapon); The only value that changed in the changeWarriorClass method was warriorProfession, because it’s a mutable StringBuilder object. Note that warriorWeapon did not change because it’s an immutable String object. The correct output from our Challenger code would be: D: Warrior=Dragon Knight Weapon=Sword. Video challenge! Debugging object references in Java Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video, you can follow along while I debug and explain object references in Java. Learn more about Java Get more quick code tips: Read all of Rafael’s articles in the InfoWorld Java Challengers series. Check out more videos in Rafael’s Java Challengers video playlist. Find even more Java Challengers on Rafael’s Java Challengers blog and in his book, with more than 70 code challenges. Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos