Pass By Value
Continue from the previous post. We are going to validate and verify whether this statement is true or not, which is Java is always pass-by-value.
Business Objects as Arguments
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.cloudberry.com.my.passbyvalue;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class PassByValueTest {
@Test
public void testPassByValueBusinessObject() {
Student student = new Student();
System.out.println("Value of name before Student modification = " + student.getName());
assertEquals(student.getName(), null);
modifyStudent(student);
System.out.println("Value of name after Student modification = " + student.getName());
assertEquals(student.getName(), "Alex");
}
@Ignore
private void modifyStudent(Student student) {
student.setName("Daniel");
}
}
Value of name before Student modification = null
Value of name after Student modification = Daniel
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.
The copy of the reference and the original reference prior to modifyStudent()
are pointing to the same object, thus any modifications to the object attributes inside the method are reflected in the original reference.
Collection Arguments
package com.cloudberry.com.my.passbyvalue;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class PassByValueTest {
@Test
public void testPassByValueCollection() {
List<Integer> lstNums = new ArrayList<Integer>();
lstNums.add(777);
System.out.println("Size of list before List modification = " + lstNums.size());
modifyCollection(lstNums);
System.out.println("Size of list after List modification = " + lstNums.size());
}
@Ignore
private void modifyCollection(List<Integer> lstParam) {
lstParam.add(333);
}
}
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 pointed and referenced by two references, and any change done by one reference is reflected in the other.
Inside the method, we called lstParam.add(333)
, 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 is modified, because of both the two references are pointing to the same object in memory.
Wrapper Class Arguments
package com.cloudberry.com.my.passbyvalue;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class PassByValueTest {
@Test
public void testPassByValueWrapper() {
Integer x = new Integer(222);
Integer y = new Integer(888);
assertEquals(x.intValue(), 222);
assertEquals(y.intValue(),888);
System.out.print("Values of x & y before wrapper modification: ");
System.out.println("x = " + x.intValue() + " ; y = " + y.intValue());
modifyWrappers(x, y);
assertEquals(x.intValue(), 222);
assertEquals(y.intValue(),888);
System.out.print("Values of x & y after wrapper modification: ");
System.out.println("x = " + x.intValue() + " ; y = " + y.intValue());
}
@Ignore
private void modifyWrappers(Integer x, Integer y) {
x = new Integer(555);
y = new Integer(777);
}
}
Values of x & y before wrapper modification: x = 222 ; y = 888
Values of x & y after wrapper modification: x = 222 ; y = 888
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.
Primitive Arguments
package com.cloudberry.com.my.passbyvalue;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class PassByValueTest {
@Test
public void testPassByValuePrimitive() {
//Init
int x = 1;
int y = 2;
//Pre-modifyPrimitiveTypes()
System.out.print("Values of x & y before primitive modification: ");
System.out.println(" x = " + x + " ; y = " + y );
assertEquals(x, 1);
assertEquals(y, 2);
modifyPrimitiveTypes(x,y);
//Post-modifyPrimitiveTypes()
System.out.print("Values of x & y after primitive modification: ");
System.out.println(" x = " + x + " ; y = " + y );
assertEquals(x, 1);
assertEquals(y, 2);
}
@Ignore
private void modifyPrimitiveTypes(int x, int y)
{
x = 5;
y = 10;
}
}
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.