Array seems to be getting passed by reference in J

2020-02-21 08:09发布

问题:

I can post more code if I need to, but before that I would like to just ask a general question about the following method in which an array is passed, and then set to another array, but for some reason the original array, the one being passed in, is also getting changed, how this possible/what should i do? Thanks

tempBoard is an array of same size as currentState, and temp[k] contains the changes that are being made in movePiece, current state is declared in the method and is not a global variable

private int[][] MiniMaxBaseCase(int[][] currentState, int currentColor)
{
    tempBoard = movePiece(currentState,temp[k]);
}

private int[][] movePiece(int[][] currentState, int[] move)
{
    if(move[0] == -1)
        return currentState;

    //if the piece is just moving
    if(move[4] == -1)
    {
        currentState[move[2]][move[3]] = currentState[move[0]][move[1]];
        currentState[move[0]][move[1]] = 0;
        return currentState;
    }

    //if the piece is jumping another
    if(move[4] != -1)
    {   
        currentState[move[4]][move[5]] = currentState[move[0]][move[1]];
        currentState[move[2]][move[3]] = 0;
        currentState[move[0]][move[1]] = 0;
        return currentState;
    }

    return currentState;
}

回答1:

In Java:

  • method arguments are indeed passed-by-value, but
  • all object and array variables in Java are reference variables.

The net effect of a reference variable being passed-by-value is that the object or array pointed to by that reference variable is passed-by-reference.

Your array was effectively passed-by-reference - its the same array.

Specifically, currentState in MiniMaxBaseCase is a reference to an array - the value of it is the memory location of the array. currentState in MiniMaxBaseCase is passed by value to movePiece, so the value of currentState in MiniMaxBaseCase (a memory location) if copied into parameter currentState in movePiece - the reference was passed by value. But now currentState in movePiece points to the same memory location as currentState in MiniMaxBaseCase. So now both variables both point to the same array, i.e. the net effect was that the array was effectively passed-by-reference.


Edit: Copying multi-dimensional arrays

Some people have been suggesting to use System.arraycopy() or Array.copyOf() directly without traversing into the first dimension/index. This won't work.

Use this instead:

public static int[][] copyOf(int[][] original) {
    int[][] copy = new int[original.length][];
    for (int i = 0; i < original.length; i++) {
        copy[i] = Arrays.copyOf(original[i]);
    }
    return copy;
}

The reason a direct copy won't work is because in Java, a 2-dimensional array is really an array of pointers/references to a collection of (scattered) 1-dimensional arrays, i.e., int[][] is an array of pointers to a bunch of (scattered) int[]. Simply doing a System.arraycopy() or Arrays.copyOf() on a 2-D array will simply copy the pointers to the scattered int[] arrays, i.e. this shallow copy ends up sharing the underlying set of arrays. You must do a deep copy as shown in the code above.

Some references:

How do I do a deep copy of a 2d array in Java?

Yes, you should iterate over 2D boolean array in order to deep copy it.

http://www.cs.dartmouth.edu/~spl/Academic/Java/JFAQs.html
How do I copy multi-dimensional arrays?

... Copying a two dimensional array is however more problematical because multi-dimensional arrays are represented as arrays of arrays. This is an issue when you are cloning an array. System.arraycopy() will give you a copy of the references to the embedded arrays. ...



回答2:

In Java there is NO SUCH THING as pass-by-reference. You seem to know that and wonder why it still feels like that this is what happens here...

Well the Problem is, that arrays are Objects. And Objects are actually Pointers. So you get a COPY of the pointer to the array, but it's still the array it is pointing to.

Use System.arraycopy() if you want to create a copy of the array before making any changes to it.



回答3:

Take some time to have a good read of this.

http://www.cs.toronto.edu/~dianeh/tutorials/params/

Skip down to "Passing Arrays"

Arrays are references. This means that when we pass an array as a parameter, we are passing its handle or reference. So, we can change the contents of the array inside the method.

This is from a course "148: Introduction to Computer Science", which should fit around the first 2 lessons on the Java language.

To pass a copy of an array to a function, in Java 1.6, you can use Array.copyOf, e.g

tempBoard = movePiece(Arrays.copyOf(currentState, currentState.length), temp[k]);

Note: Array.copyOf is only good for single-dimension array of primitives. Used on anything else, it gives you an independent array, with all elements IDENTICAL and pointing to the original array, be it Objects or nested arrays.