Search code examples
javapass-by-referencepass-by-value

Java - Pass by value: Why does the list change when being handed over to another class?


I'm working on a Java question for my school which gives me this utility class:

import java.util.*;

public class PassByValue
{

    private PassByValue() {}

    public static void add(int a)
    {
        a = a + 1;
    }

    public static void add(Set<String> b)
    {
        b = new HashSet<String>();
        b.add("ABC");
    }

    public static void add(List<Integer> c)
    {
        c.add(new Integer(1));
    }
}

It also gives me this class with the main method

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class PassByValueClient
{
    public static void main(String[] args)
    {
        PrintStream output = System.out;

        int a = 1;
        PassByValue.add(a);
        output.println(a);

        Set<String> b = new HashSet<String>();
        PassByValue.add(b);
        output.println(b.size());

        List<Integer> c = new ArrayList<Integer>();
        PassByValue.add(c);
        output.println(c.size());
    }
}

We are supposed to predict the output. When I predicted what the output would be, my guess was 1, 0, and 0 respectively. However, when I ran the code the output I got was 1, 0, and 1 respectively. From what I understand about passing parameters/arguments into methods, the client's code should remain unchanged. Can someone tell me why the output is 1 instead of 0?


Solution

  • This is because the List, which gets handed over to PassByValue.add() points to a place in your storage (the address), the place (say the address 42) of your list. And when the list is in the method .add(), it still points to the same address (42)

    If you change it, the data on that address (42) gets changed too. But both lists still point to the same address (42), so they point to the same data.

    I'd like to explain whats happening in your example with pictures:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Variable "a"

    Integer a = 1
    

    This creates an address in your storage, to which the variable a points to: 1_a

    When you then pass it to the method PassByValue.add(a) a new variable is created. But this new variable points to the same address (value).

    enter image description here

    When you then change it with a = a+1, the variable doesn't point to the address anymore, but to a new one, with a new value. enter image description here

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Variable "b"

    When you declare it an object is created pointing to a specific address:

    enter image description here

    When you hand it over there is another object created, which points to the same address:

    enter image description here

    When you set the object in PassByValue.add() to = new HashSet<String>();, it points to another address.

    enter image description here ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Variable "c"

    Thats different when you change the object ITSELF.

    Like you do it with the list. By creating the List List<Integer> c = new ArrayList<>(); the variable points to a specific address.

    enter image description here

    When you hand it over to the .add()-Method, a new variable is created, but it points to the same address.

    enter image description here

    And when you then change it by saying c.add(new Integer(1)); You change the object ITSELF. When you change the object ITSELF, the data stored on that address gets changed, but no new address-space gets created and both variables still point to the same address. enter image description here