- Which arguments pass by value and which pass by reference in Java?
- 2 Answers 2
- Java: What to Know About Passing by Value
- 1. by value vs. by reference
- 2. how arguments are passed in java
- 3. fixing some concerns
- passing primitive arguments
- passing wrapper arguments
- passing collection arguments
- passing business objects as arguments
- conclusion
Which arguments pass by value and which pass by reference in Java?
I am starting to learn Java with the Java Trails tutorials offered by Oracle. I am in the section where it talks about passing arguments to methods The Java™ Tutorials: Passing Information to a Method or a Constructor. It says that primitive types are passed by value, which makes sense to me. Right after that it says:
Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object’s fields can be changed in the method, if they have the proper access level.
Now this doesn’t make sense to me. If an object is passed by value, then changing the fields of that object will change the fields of the copy inside the method, not the original one. When testing with the program below:
You are right, @daniels: class instances (objects) are passed by reference in the literal sense: through passing the reference (pointer) by value.
This is a very common question, the definitive answer is, imho, Parameter passing in Java — by reference or by value
The implicit references are a characteristic of objects, not of parameter passing. For example object variables are implicitly «by-reference» too. Another way to explain it is that Java objects have reference semantics, whereas (most?/all?) other types have value semantics.
2 Answers 2
Java is pass by value. Think of it like a pointer language like C, the value of the pointer (memory address) is being passed, so you have a reference to the same object. Primitives aren’t stored internally the same way as Objects, so when you pass a primitive’s value, it’s the content, not a pointer.
Gotcha, so when you pass the name of an object to a method you are actually passing a copy of it’s memory address, right?
Internally, yes. Though, if you were to pass an object (reference), say method(cat) , the local variable holding the reference copied from cat could be changed to point to a new object, without changing the actual reference stored in cat .
Right. And I guess that’s the reason we say that objects are passed by value (i.e., the value of their addresses). If they were passed by reference in the real sense of the word doing an attribution on the «cat» inside the method would also affect the original one. Correct?
@daniels: To avoid confusion, it is important to be very precise about terms. Java objects do not have names. Variables have names. A variable can store an object reference or a primitive value.
This specific kind of call-by-value-where-the-value-is-a-pointer is also called call-by-sharing or call-by-object-sharing. IOW: the caller and the callee have different pointers, but they may point to the same (mutable) object. Mutability is what is important here: for immutable objects call-by-value-where-the-value-is-passed-directly and call-by-sharing are actually indistinguishable.
There is a test for whether a language is pass-by-reference: can you write a swap function, such that after swap(a,b), the caller finds that the values of a and b are reversed? You cannot do this in Java, not even for objects.
Note that you cannot achieve this goal by swapping the internals of the two objects — while the data may change, the identity of the objects has not, and this has consequences. For one thing, any other variable in the program that referenced either object would also see the change.
To see why you cannot write this swap, consider a simplified model of the language, in which the value of a reference variable is the address of the object it is currently bound to (garbage collection complicates this picture in a way not relevant here.) Before the call to swap, the caller’s stack frame has a slot for a, containing the address of object A, and a slot for b containing the address of B. When swap is called, it receives the values of a and b, which are the addresses of A and B respectively. Therefore, it is decoupled from the caller: there is simply no way for it to find the addresses of the slots for a and b within the caller’s stack frame, and therefore no way to set them so that the caller will see them swapped.
@supercat suggests an alternative way of looking at it: conceptually, a reference variable holds the unique ID of the object it references, something that is fixed for the life of the object, and it is this that gets copied to the function in a call. This view also makes it clear that the function has no way to find, let alone modify, the variable in the caller’s stack frame.
Call-by-reference means exactly the opposite, by definition: the function accesses its arguments through the caller’s variable bindings, so that changing one of its arguments’ binding in the function necessarily changes it in the caller’s stack frame. The term dates to a time when mainstream languages did not have objects or references as first-class entities, and when an argument was passed, either a copy of its value (in pass-by-value) or its address (in pass-by-reference) was pushed on to the stack so that the function could retrieve it. Passing an argument’s address allows swap to work, but passing an address it contains does not.
Another way of looking at it: pass-by-reference does not mean pass the reference held in the argument variable, it means create, in the function, a local variable that references the argument variable.
Therefore, we can see that Java uses pass-by-value, not pass-by-reference.
See also Java is Pass-by-Value, Dammit! which also discusses argument-passing in Java RMI.
Java: What to Know About Passing by Value
Join the DZone community and get the full member experience.
before describing how arguments are passed in java, it is worth defining how java variables are allocated in memory. basically, we’re talking about two types of variables: primitives and objects.
primitive variables are always stored inside the stack memory ( the memory space that holds method-specific variables that are short-lived in addition to references to other objects in the heap ).
however, objects are stored at two stages. the actual object data is stored inside the heap memory ( the memory space that holds objects and jre classes ), and a reference for the object is kept inside stack memory, which just points to the actual object.
1. by value vs. by reference
what is meant by «by value» and «by reference» :
- by value: when arguments are passed by value to a method, it means that a copy of the original variable is being sent to the method and not the original one, so any changes applied inside the method are actually affecting the copy version.
- by reference: when arguments are passed by reference, it means that a reference or a pointer to the original variable is being passed to the method and not the original variable data.
2. how arguments are passed in java
in java, arguments are always passed by value regardless of the original variable type. each time a method is invoked, a copy for each argument is created in the stack memory and the copy version is passed to the method.
- if the original variable type is primitive, then simply, a copy of the variable is created inside the stack memory and then passed to the method.
- if the original type is not primitive, then a new reference or pointer is created inside the stack memory, which points to the actual object data, and the new reference is then passed to the method, (at this stage, two references are pointing to the same object data).
3. fixing some concerns
in the following example, we try to validate that «java is always pass-by-value» by passing several argument types (primitive, wrappers, collections, business objects) and checking whether they are modified after the method call.
passing primitive arguments
public static void main(string[] args) < int x = 1; int y = 2; system.out.print("values of x & y before primitive modification: "); system.out.println(" x = " + x + " ; y = " + y ); modifyprimitivetypes(x,y); system.out.print("values of x & y after primitive modification: "); system.out.println(" x = " + x + " ; y 140">
output:
values of x & y before primitive modification: x = 1 ; y = 2 values of x & y after primitive modification: x = 1 ; y = 2
the two variables, x and y , are of primitive types and are thus stored inside the stack memory. when calling modifyprimitivetypes() , two copies are created inside the stack memory (let's say w and z) and are then passed to the method. hence, the original variables are not being sent to the method and any modification inside the method flow is affecting only the copies.

passing wrapper arguments
public static void main(string[] args) < integer obj1 = new integer(1); integer obj2 = new integer(2); system.out.print("values of obj1 & obj2 before wrapper modification: "); system.out.println("obj1 = " + obj1.intvalue() + " ; obj2 = " + obj2.intvalue()); modifywrappers(obj1, obj2); system.out.print("values of obj1 & obj2 after wrapper modification: "); system.out.println("obj1 = " + obj1.intvalue() + " ; obj2 138">
output:
values of obj1 & obj2 before wrapper modification: obj1 = 1 ; obj2 = 2 values of obj1 & obj2 after wrapper modification: obj1 = 1 ; obj2 = 2
wrappers are stored inside the heap memory with a correspondent reference inside the stack memory.
when calling modifywrappers() , a copy for each reference is created inside the stack memory, and the copies are passed to the method. any change to the reference inside the method is actually changing the reference of the copies and not the original references.

p.s: if you change the value of wrapper objects inside the method like this: x += 2, the change is not reflected outside the method, since wrapper objects are immutable. they create a new instance each time their state is modified. for more information about immutable classes, check out "how to create an immutable class in java" . string objects work similarly to wrappers, so the above rules apply also on strings.
passing collection arguments
public static void main(string[] args) < listlstnums = new arraylist(); lstnums.add(1); system.out.println("size of list before list modification = " + lstnums.size()); modifylist(lstnums); system.out.println("size of list after list modification 136">
output:
size of list before list modification = 1 size of list after list modification = 2
when defining an arraylist or any collection in java, a reference is created inside the stack that points to multiple objects inside the heap memory. when calling modifylist(), a copy of the reference is created and passed to the method. the actual object data is referenced by two references, and any change done by one reference is reflected in the other.
inside the method, we called lstparam.add(2) , which actually tries to create a new integer object in the heap memory and link it to the existing list of objects. hence the original list reference can see the modification, since both references are pointing to the same object in memory.

passing business objects as arguments
public static void main(string[] args) < student student = new student(); system.out.println("value of name before student modification = " + student.getname()); modifystudent(student); system.out.println("value of name after student modification = " + student.getname()); >private static void modifystudent(student student)
value of name before student modification = null value of name after student modification = alex
the student object is created inside the heap space, and a reference for it is defined inside the stack. when calling modifystudent(), a copy of the reference is created inside the stack and passed to the method. any modifications to the object attributes inside the method are reflected in the original reference.
conclusion
in java, arguments are always passed by value. the copy would be either a reference or a variable depending on the original variable type. from now on, you can use the following tips in order to understand how modifying arguments inside methods affects the original variable:
- modifying the value of a primitive argument would never affect the original variable.
- changing the reference to an object argument inside the method would never affect the original reference. however, it creates a completely new object in the heap space.
- modifying the attributes of an object argument inside a method is reflected outside of it.
- modifying collections and maps inside the method is reflected outside of them.
Published at DZone with permission of Hussein Terek , DZone MVB . See the original article here.
Opinions expressed by DZone contributors are their own.