views:

1866

answers:

5

Hello,

I have a problem with understanding the "pass-by-value" action of Java in the following example:

public class Numbers {

    static int[] s_ccc = {7};
    static int[] t_ccc = {7};

    public static void calculate(int[] b, int[] c) {

     System.out.println("s_ccc[0] = " + s_ccc[0]); // 7
     System.out.println("t_ccc[0] = " + t_ccc[0]); // 7

     b[0] = b[0] + 9;  
     System.out.println("\nb[0] = " + b[0]); // 16

     c = b;
     System.out.println("c[0] = " + c[0] + "\n"); // 16
    }

    public static void main(String[] args) {

     calculate(s_ccc, t_ccc);

     System.out.println("s_ccc[0] = " + s_ccc[0]);  // 16
     System.out.println("t_ccc[0] = " + t_ccc[0]);  // 7 
    }
}

I know that because s_ccc is a reference variable, when I give it to the method calculate() and I make some changes to its elements in the method, the changes remain even after I leave the method. I think that the same should be with t_ccc. It is again a reference variable, I give it to the method calculate(), and in the method I change the referece to t_ccc to be that of s_ccc. Now t_ccc should be a reference variable pointing to an array, which has one element of type int equals to 16. But when the method calculate() is left, it seems that t_ccc points its old object. Why is this happening? Shouldn't the change remain for it, too? It is a reference variable after all.

Regards

+6  A: 

There's an extended discussion of how Java passes variables at an earlier question "Is Java pass by reference?". Java really passes object references by value.

In your code, the references for the arrays (which are objects) are passed into calculate(). These references are passed by value, which means that any changes to the values of b and c are visible only within the method (they are really just a copy of s_ccc and t_ccc). That's why t_ccc in main() was never affected.

To reinforce this concept, some programmers declare the method parameters as final variables:

public static void calculate(final int[] b, final int[] c)

Now, the compiler won't even allow you to change the values of b or c. Of course, the downside of this is that you can no longer manipulate them conveniently within your method.

Zach Scrivena
+5  A: 

The method receives variables by value. Those values can't be changed (as far as the caller of the method sees), but the values contained within them can (if it's an object, or as in this case, an array).

So when you change the value b[0] inside the array, the change can be seen outside the method. However the line

c = b;

will change the value of c inside the method, but that change will not be seen outside the method, since the value of c was passed by value.

Kieron
+4  A: 

The line calculate(s_ccc, s_ccc); indicates you're not actually doing anything to t_ccc. However, should this line have read calculate(s_ccc, t_ccc); than the effect remains the same.

This is due to the fact that you're assigning a new value to c here: c = b;
When assigning a new value to a reference argument the reference is lost.
This is the difference between altering a by reference variable and assigning a new value.

Tim
+1  A: 

On entry to calculate(), b points at s_ccc and c points at t_ccc. Altering b[0] will therefore change s_ccc, as you've seen.

However, the assignment

c = b;

only points c at the same object b is pointing at, namely s_ccc. It does not copy the contents of what b points to to what c points to. As a result, t_ccc is unchanged. If you added the following line to the end of calculate():

c[0] = c[0] + 5;

s_ccc[0] would be 21.

Pourquoi Litytestdata
+4  A: 

Here's a simple way to understand it.

Java always passes copies of arguments. If the argument is a primitive type (e.g. an integer), then the called method gets a copy of the primitive value. If the argument is a reference type, then the called method gets a copy of the reference (not a copy of the thing referred to).

When your main method begins, each of s_ccc and t_ccc refers to a distinct array. This is the situation, where parentheses indicate variables and square brackets indicate the actual array structures:

(s_ccc) ---> [7]
(t_ccc) ---> [7]

Assuming that you meant calculate(s_ccc, t_ccc), then at the beginning of the calculate method:

(s_ccc) ---> [7]  <---(b)
(t_ccc) ---> [7]  <---(c)

Locals b and c are copies of globals s_ccc and t_ccc respectively.

Still within calculcate, after b[0] = b[0] + 9 has completed:

(s_ccc) ---> [16] <---(b)
(t_ccc) ---> [7]  <---(c)

The zero (only) position in the array referred to by b has been modified.

The assignment c = b within calculate produces this situation:

(s_ccc) ---> [16] <---(b)
               ^------(c)
(t_ccc) ---> [7]

The local reference variable c, now contains the same reference as b. That has no effect on the global reference variable t_ccc, which still refers to the same array as before.

When calculate exits, its local variables (on the right-hand side of the diagrams) disappear. The global variables (on the left-hand side) were not used in calculate, so they are unaffected. The final situation is:

(s_ccc) ---> [16]
(t_ccc) ---> [7]

Neither c_ccc nor t_ccc were changed; each still refers to the same array as before calculate. Calling calculate changed the content of the array referenced by s_ccc, using a copied reference to that array (in b).

Local variable c started as a copy of t_ccc and was manipulated within calculate, but that changed neither t_ccc itself nor it's referenced data.

joel.neely