Change value of variable added to stack without changing stack?

I have a stack of arrays. I also have an array that I push into the stack, modify, and push again. Whenever I change the value of the array, all variables within the stack are modified the same way. For example:

int[] array = {1, 1};
Stack<int[]> stack = new Stack<int[]>();
stack.push(array);
array = {1, 3};
stack.push(array);

The stack should be {{1, 1}, {1, 3}} but instead it’s {{1, 3}, {1, 3}}. I’ve tried stack.push({1, 3}); but that results in an error. I also can’t declare a new array every time because this whole thing is happening in a loop.

Answer

Your code does not compile. Let’s disregard the part that doesn’t compile and explain java.

I also can’t declare a new array every time because this whole thing is happening in a loop.

Nono. You can. int[] is an object type (in contrast to a primitive type). That means the variable actually represents a treasure map, and not the treasure. So, let’s break it down:

int[] array = {1, 1};

This is just syntax sugar for:

int[] array = new int[] {1, 1};

which is just syntax sugar for:

int[] array = new int[2];
array[0] = 1;
array[1] = 1;

Furthermore, the new int[2] command creates new treasure and buries it in the sand, and the int[] array part makes a new treasuremap, and the = in the middle scribbles a nice X-marks-the-spot on your map. [] and . are java-ese for: Walk to the X and dig down. = is java-ese for: Take an eraser and wipe that X away, then place it somewhere else.

Also, in java, whenever you pass stuff to methods, it’s always copies (but, copies of the map, not copies of the treasure).

That way of thinking about it is precisely how the java memory model works and will never steer you wrong. Thus:

int[] array = {1, 1};
// 1 treasure chest made.
// 1 treasure map made. The map is called `array`.
// X marked on the map.

stack.push(array);
// Take your `stack` map, walk to the X. Dig down.
// Open the chest you find here, and yell into it: "push".
// Make a copy of your `array` map, and hand it over.

array = {1, 3};
// This isn't legal java.

array[1] = 3;
// This takes your array map, follows the X,
// digs, tosses out the second element you find
// in the box, and then puts a 3 in there instead.

Of course the stack sees the same 3: There is only one treasure, and you both have a map to it.

Let’s fix it. Remember, = wipes out the X, and new makes new treasure. We want 2 treasures here: One is {1, 1}, and the other is {1, 3}. So, new is involved, and = is useful too. Let’s use them:

int[] array = {1, 1};
stack.push(array);

array = new int[] {1, 3};
// The above is the syntax for making a new int array.

stack.push(array);
System.out.println(stack);

success! Now it works.

The reason int[] x = {1, 3}; is legal, but x = {1, 1}; is not, is a quirk of the language. It’s in the language specification. int[] x = ... is declaring a new variable with an initializer, whereas x = ... is an assignment expression.

Java needs to know the type of the array you want to make. It’s very obvious when writing int x = { ... }. It is slightly less obvious when you write x = { ... } which is presumably why the spec doesn’t allow the shorthand. Note that it is perfectly fine to write int[] x = new int[] {1, 3}; as well; int x[] = {1, 3}; is merely convenient shorthand.

// This takes your array map, follows the X, // digs, tosses out the second element you find // in the box, and then puts a 3 in there instead.

Leave a Reply

Your email address will not be published. Required fields are marked *