2

I was playing with arrays and manipulating them in different ways, and I stumbled across some very strange behavior! My initial concern was replacing an array with another one that might or might not be a different size, since it would be reading from a file of an arbitrary length. I decided to play with different things to see what all would happen. My first attempt was this:

public class RewriteArray {
    public static void main(String[] args) {
        String[] arr = { "1", "2", "3"};

        System.out.print("Before rewrite: ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();

        changeArr(arr);

        System.out.print("After rewrite:  ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();
    }

    private static void changeArr(String[] arr) {
        arr[0] = "3";
        arr[1] = "2";
        arr[2] = "1";
    }
}

This did what I expected, proving the change by referenced object, and gave the output:

Before rewrite: 1 2 3
After rewrite:  3 2 1

I then tried resizing the array within the changeArr method, and that's when things got weird.

public class RewriteArray {
    public static void main(String[] args) {
        String[] arr = { "1", "2", "3"};

        System.out.print("Before rewrite: ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();

        changeArr(arr);

        System.out.print("After rewrite:  ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();
    }

    private static void changeArr(String[] arr) {
        arr = new String[4];
        arr[0] = "3";
        arr[1] = "2";
        arr[2] = "1";
        arr[3] = "0";
    }
}

I would have expected arr to be replaced by a new object of the new size and then rewritten. Instead, I got:

Before rewrite: 1 2 3
After rewrite:  1 2 3

No errors or anything, but no changes in the array whatsoever! I then tried to resize the initial array by making a temporary one and re-assigning the pointer.

private static void changeArr(String[] arr) {
    String[] tempArr = new String[4];
    tempArr[0] = "3";
    tempArr[1] = "2";
    tempArr[2] = "1";
    tempArr[3] = "0";
    arr = tempArr;
}

Again, the output was identical to the previous version! No errors, but no changes either. Just to be completely sure it was at least POSSIBLE to resize an array, I tried creating a temporary array in a separate method and returning the array.

public class RewriteArray {
    public static void main(String[] args) {
        String[] arr = { "1", "2", "3"};

        System.out.print("Before rewrite: ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();

        arr = loadArr();

        System.out.print("After rewrite:  ");
        for (String str : arr)
            System.out.print(str + " ");
        System.out.println();
    }

    private static String[] loadArr() {
        String[] tempArr = new String[4];
        tempArr[0] = "3";
        tempArr[1] = "2";
        tempArr[2] = "1";
        tempArr[3] = "0";

        return tempArr;
  }
}

This time it finally worked! I got the following output:

Before rewrite: 1 2 3
After rewrite:  3 2 1 0

It certainly seems at this point that it's best to have to create the new temporary array in the separate method and return that array, then assign the returned array to the original one. I just don't understand why it's not working with the changeArr method internally. Isn't this passing references internally? If it wasn't, why would my first attempt work while the others didn't?

BrainFRZ
  • 437
  • 3
  • 15
  • 3
    Read this: http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value?rq=1 – Thilo Mar 08 '16 at 01:36
  • @Thilo Why don't you just mark it as a duplicate? – Erwin Bolwidt Mar 08 '16 at 01:44
  • 1
    Java is always pass-by-value. It just also happens to have reference semantics. This can be confusing at first. – Ian McLaird Mar 08 '16 at 01:45
  • @Erwin: If I mark as dupe it closes the question instantly. I want a second opinion. I would close for a duplicate that is specificly about arrays (which there must be). – Thilo Mar 08 '16 at 01:46
  • I don't see how this is duplicate to the other question. This has to do with replacing the object with a different one, and asks much more specifically in practice with arrays. The other question had to do with just asking about how the objects were passed. Also, in the top answers, it talks about parameters being an alias to the variable being passed. Isn't that exactly what a reference is? – BrainFRZ Mar 08 '16 at 01:54
  • @Thilo No one has ever asked this question regarding arrays that I can see. If they have, would you please show me? To me at least it's not entirely clear why the arrays would behave in the same way. If there was an answer specifically regarding arrays, it would be far more helpful. You say "there must be," but how can they be if they've all been marked as duplicate? – BrainFRZ Mar 08 '16 at 02:09
  • 1
    In Java `Array`s *are* objects, and they behave in exactly the same way in all cases (their members just happen to be accessed by index). It's easiest in Java to think of parameters as just being a local variable that gets initialized from the passed in value, and then discarded when the method goes out of scope. – Ian McLaird Mar 08 '16 at 02:10

2 Answers2

5

Java passes references by value

Changing the parameter to refer to a new instance has no effect on the expression that you passed as the parameter.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 2
    Which means: you can change values inside of the array (and the caller will see that, because it's still the same array), but if you change the local variable to a new array, the caller doesn't care. – Thilo Mar 08 '16 at 01:37
0

In your changeArr() method, when you did the following initializaition

arr = new String[4];

you actually assigned a local variable to point to a newly allocated array. The original array which was passed in remained unaffected.

You can't resize an array in Java. The closest thing to achieving this would be to use something like java.lang.System.arraycopy() which returns an enlarged copy of your original array. Or you could try using an ArrayList which was designed with this purpose in mind.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • But I did resize the array successfully in my final attempt, didn't I? And in my first attempt, `arr` was also "local", but still changed the values of the cells of the original array as we saw. – BrainFRZ Mar 08 '16 at 01:40
  • No, I don't believe this be correct. – Tim Biegeleisen Mar 08 '16 at 01:41
  • No, you didn't resize anything. You created a new, larger, array, and then discarded the original. You can change the values in the original array, but you can't change the array itself. – Ian McLaird Mar 08 '16 at 01:42
  • In your final example, you *returned* the new array from the function and *assigned* the new array to the caller's variable as well. – Thilo Mar 08 '16 at 01:43