Call by reference or Call by value

1.4k Views Asked by At

Could somebody please explain how this program is executed?

Here is the code whose output I just can't quite seem to get it:

    class Box {
        int size;
        Box (int s) {
           size = s;
        }
    }
    public class Laser {
        public static void main(String[] args) {
            Box b1 = new Box(5);
            Box[] ba = go(b1, new Box(6));
            ba[0] = b1;
            for(Box b : ba)
                System.out.println(b.size + " ");
        }

        static Box[] go (Box b1, Box b2) {
            b1.size = 4;
            Box[] ma = {b2, b1};
            return ma;
        }
    }

The actual output when I run this is 4, 4. But according to my understanding this should be 5, 4. Can anyone please help understand how this is being executed?

7

There are 7 best solutions below

3
On BEST ANSWER

When you pass an object as a parameter, you're actually passing a copy of a reference to it. That is, if you modify the parameter object inside the method, the object will retain those modifications when that method returns, which is why you see b1 retaining the size = 4 assignment after go returns.

0
On

If the function 'go' in the original post is in C (and b1 and b2 are C pointers), it can do the following two things (which the caller will see):

  1. Change the value of variables in the data structures pointed to by b1 and b2.
  2. Make the original b1 and b2 point to different data structures.

In Java, we can do 1 but NOT 2, since go does not have access to the original b1 and b2. (It has access to copies of b1 and b2. At the beginning of the subroutine, the copy b1 points to the same object as the original b1 and so on.)

Saying Java is pass by call DOES miss something, namely the ability of the function to do 1, i.e., change the properties of the object in the heap referenced by b1 and b2. [This is what happens in the statement, b1.size = 4;, which caused the original poster's confusion.]

b1 in 'go' is NOT the same location as b1 in 'main'. However, when the function starts, b1 in 'go' references the same object as b1 in 'main' and any changes made to the object using b1 in 'go' will be seen when b1 in 'main' is used as the reference.

However, if b1 in 'go' is set to another Box, b1 in 'main' will NOT see this; it will still see the previous Box.

6
On

In Java, objects are passed by reference, primitives are passed by value.

public class Laser {
    public static void main(String[] args) {
        //Create a Box of size 5.
        Box b1 = new Box(5);
        //Create an array of Box objects, which are the results of the go method
        Box[] ba = go(b1, new Box(6));
        // ba now looks like {new Box(6), b1 /*b1 is size 4 now*/}
        // assign reference to b1 at index 0 in ba.
        ba[0] = b1;
        // array now looks like {b1, b1}
        for(Box b : ba)
            System.out.println(b.size + " ");
    }

    static Box[] go (Box b1, Box b2) {
        //set the size of the first box to 4
        b1.size = 4;
        //create an array of boxes, with b2 in index 0 and b1 in index 1
        Box[] ma = {b2, b1};
        return ma;
    }
}
5
On

Java always passes references to objects in method calls. When you're calling go, the first argument (b1), is a reference to the same b1 Box that you have in your main. You then modify that object, whose size is now 4.

2
On

I have added the comments for you;

The important TWIST that you missed here is;

Box[] ma = {b2, b1}; its not {b1,b2}. Memory locations are interchanged while returning.

       public static void main(String[] args) {
            Box b1 = new Box(5);                 // b1 == location A
            Box[] ba = go(b1, new Box(6));       // ba == location B which stores Location A, D

           // PLEASE NOTE HERE
           // After the function go() is executed;
           // ba[] will have {D, A}
           // So ba[0] will have object b1 which is at location A. 

            ba[0] = b1;                          // location B will now store A and A
            for(Box b : ba)
                System.out.println(b.size + " ");  //  Output: 4 and 4
        } 

        static Box[] go (Box b1, Box b2) {        // go(location A, location D )
            b1.size = 4;                          // A's object.size = 4
            Box[] ma = {b2, b1};                  // position is interchanged here (D and A)
            return ma;                            // return the location of ma
        }

Hope this helps.

Do let me know if you have any questions. Everything is pass by value in java. The memory addresses are passed by value.

0
On

The values passed to go are references to the objects. If you're coming from C, you can think of the parameters as having pointer types, something like

Box** go (Box *b1, Box *b2) {
     b1->size = 4;
     /* allocate an array of Box*, set it up, return it */
}

(Sorry if I got the C syntax wrong.) The pointers (references) themselves are passed by value, which means that if you say inside "go" (in the C program):

b1 = &some_other_box;

it doesn't affect any variables on the calling side, and it works the same way in Java. This makes it a bit different than a var parameter in PHP or Pascal.

0
On

Java passes copies of references to objects in method calls.

You can't change an object by assigning to it.

public static void main(String[] args) {
    Box b1 = new Box(5);
    Change(b1);
    System.out.println(b1.size + " ");

static void Change(Box b1) {
    b1 = new Box(6);
}

This will always return 5, because the function Change only overwrites the copy to the referenced object.

You can however affect the object's properties like so:

public static void main(String[] args) {
    Box b1 = new Box(5);
    Change(b1);
    System.out.println(b1.size + " ");

static void Change(Box b1) {
    b1.size = 6;
}

This will return 6 (the reference to the object remains unchanged).