java
java

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

Student.java
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");
	}
}
Output

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);
	}
}
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 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);
	}
}
Output
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;
	} 
}
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.

Source Codes

https://github.com/wuchiachong/java-passbyvalue

Last modified: June 26, 2018

Author