smatter
smatter

Reputation: 29248

Passing by reference in Java

How can I pass an array by reference in Java? For instance I need to do some operations on the arrays A and B and populate the array C which should be available to the caller.

  public boolean Operate(int[] A, int[] B, int[] C)
  {
     //Write into the empty array C by manipulating values of A and B  and it should be accessible to caller
  }

I read that unlike C#, pass by reference is not there in Java. In that case what is the best way to do this.

Upvotes: 0

Views: 258

Answers (7)

Adam Paynter
Adam Paynter

Reputation: 46948

In Java, arrays are reference types, not value types. This means that array variables only store references to the actual array.

For example, consider this code:

int[] numbers = new int[3];

In this example, numbers is a reference to an array of 3 ints. This can be illustrated as follows:

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+---+
   | numbers |-------------->| 0 | 0 | 0 |
   +---------+       |       +---+---+---+
                     |         0   1   2

Now suppose you have a method like this:

public void compute(int[] someValues) {
    someValues[2] = 78;
}

And suppose you call this method with your numbers variable as the argument:

int[] numbers = new int[3];
compure(numbers);

In this case the numbers reference is passed by value to compute. Therefore, someValues is a copy of the numbers reference (not a copy of the array that numbers refers to). Therefore, it looks something like this:

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+---+
   | numbers |-------------->| 0 | 0 | 0 |
   +---------+       |   --> +---+---+---+
                     |  /      0   1   2
   +------------+    | /
   | someValues |-----/
   +------------+    |

After compute returns, it will look like this:

    Java Stack       |         Java Heap
                     |
                     |       Array of ints:
   +---------+       |       +---+---+----+
   | numbers |-------------->| 0 | 0 | 78 |
   +---------+       |   --> +---+---+----+
                     |  /      0   1   2
   +------------+    | /
   | someValues |-----/
   +------------+    |

numbers[2] will be equal to someValues[2] because numbers and someValues reference the same array.

Sigh, it appears this has been answered similarly since I began writing my answer. Hopefully the ASCII diagrams make it worth keeping!

Upvotes: 3

Jean Hominal
Jean Hominal

Reputation: 16796

As you said, passing an argument by reference is not possible in Java.

Here are a few workarounds for your problem:

  1. If you already know how big the array C should be - or you just want the method to make changes to the array without reassigning it. Then your method will work fine. Just do not assign the C variable.
  2. See Philip Goh's answer - return an array and check on the function's return value (null or not) to replace the boolean.
  3. If you don't know how big the array C should be and want to use the same signature - then pass an empty List<Integer> to the function, and convert it to an array afterwards.
  4. You could also create a ReferenceArgument<T> class, that could be implemented by:

    public final class ReferenceArgument<T> {
        public T obj = null;
        // You could also make the field private and use getter/setter methods.
    }
    

    I would recommend against that however - but I believe that it wouldn't work with arrays (which don't mix well with generics) - and it would box primitive types, which is somewhat clumsy.

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533880

All parameters are passed by value. However in your case, you have a reference which is passed by value (not the data in the array). This means the reference is copied and cannot changed, but the data it references can be changed. e.g.

// doesn't work because it doesn't change the caller's x and y
public static void swapReferences(int[] x, int[] y) {
   int[] t = x;
   x = y;
   y = t;
}

int[] x, y;
swapReferences(x, y);
// x and y are unchanged and point to the same arrays with the same data.

// swap the contents
public static void swapContents(int[] x, int[] y) {
   int[] t = new int[x.length];
   System.arraycopy(x,0,t,0,x.length);
   System.arraycopy(y,0,x,0,x.length);
   System.arraycopy(t,0,y,0,x.length);
}

swapContents(x, y);
// x and y are unchanged but the data they refer to has been swapped.

Upvotes: 1

Martin Algesten
Martin Algesten

Reputation: 13620

You are always passing an array by reference in java. The only objects not passed by reference (but passed by value) are the primitives, int, long, boolean, double, float etc. Everything else is an object and passed by reference. So your code will work fine.

Edit: I humbly admit my foolish mistake. You are always passing by value in java. But objects are always passed with reference as value.

Upvotes: -2

user166390
user166390

Reputation:

You are getting the term 'pass by reference' confused with 'pass (the reference of an object) by value' (which is what Java and C#, without out/ref do). In the above, if the contents of A, B or C are changed, they are changed because NO NEW OBJECT IS CREATED/CLONED/DUPLICATED when they are passed to the method. In C#, 'ref' and 'out' how one uses 'pass by reference'. Note that when 'pass by reference' is used, assigning to a variable changes the value of the variable pass in by the caller (this is not possible in Java).

See Wiki: Evaluation Strategies.

Edit: If you really wish to follow this approach, remember that the calling convention does not dictate object mutability. Consider the following:

void merge(int[] A, int[] B, int[][] C) {
    int[] t = internalMerge(A, B);
    C[0] = t;
}
int[][] icky = new int[1][0];
merge(..., ..., icky);
int[] r = icky[1];

However, I would simply structure the code better. There is very little reason to use this approach and it introduces more side-effects and state mutations. As you can see, there is already a run-time error that the above code introduces. As others have suggested, why not simply return the more appropriate value?

Upvotes: 3

AlexR
AlexR

Reputation: 115398

I believe that you are a little bit confused with terminology. Do not worry. In java everything except primitives is passed by reference. In case of your array you can fill it in your method and the changes will be visible for caller.

Upvotes: -2

CadentOrange
CadentOrange

Reputation: 3343

I'm assuming that you're returning a boolean from the method to indicate success or failure.

Instead of returning a boolean, you could return array C from the function. If C is null, you know the function failed. If not, the function succeeded.

Upvotes: 1

Related Questions