I have a 2D array called "playingField". Before any alterations take place, I make a tempField 2D array and set tempField = playingField.
After several modifications, which all work, I get to this point in the code:
else {
//at this point both playingField and tempField are unchanged still
boundsNormal = bounds.OutOfBounds(move.MovePlayer(playingField,trekker, direction, rowT, colT));
if(boundsNormal == true){
//for some reason, at this point, tempField gets reassigned to the new playingField (which I'm still not sure why *THAT* changes)
playingField = tempField;
MovePlayer is a method that modifies the 2D array it takes (in this case, playingField), and OutOfBounds returns true or false, given an array.
I can maybe understand why playingField is being changed, but have no idea why tempField should experience any alteration after I initialize the boundsNormal variable.
I make a tempField 2D array and set tempField = playingField.
What you're saying doesn't make sense. You're making an array variable called tempField, but if you do
tempField = playingField
then both variables now point to the same array. So they are both being changed because they are the same array.
To avoid this, you can generally use System.arrayCopy instead of =. However, for a 2-dimensional array it's a little more complicated to "deep copy" it, because you have an array of arrays.
(Note: More generally, when objects are mutable, you may need to "deep copy" or "deep clone" them instead of use =, to avoid this problem. Arrays are just one example of this general rule.)
playingField = tempField;
This line of code does not copy your array, it copies the reference. After this assignment both playingField and tempField represent the same array in the memory (the array represented by playingField before this is probably waiting to be garbage collected.) Therefore, if after this you change anything in the array represented by playingField, the changes will also be visible in tempField, as it is basically the same array now (not copied array, just the same array with two names).
Related
This question already has answers here:
Modify list has an affect on another list in java
(2 answers)
Closed 1 year ago.
While writing a piece of code, I observed an unusual behaviour.
There is a class object obj1 which has an array list of another class object obj2 called as list1. See the code for reference:
PriorityQueue<Obj2> pq = new PriorityQueue<>(Comparator);
pq.addAll(new ArrayList<>(obj1.getList()));
Obj2 obj2 = pq.poll();
obj2.setField("any value");
System.out.println(obj2);
System.out.println(obj1.getList().get(0));
Both of the sout statement above prints the value.
Why is this happening? I changed the value of obj2 reference in pq and not in Obj1 itself
While adding elements to the pq, if we don't use new ArrayList<>() then it's understandable if the both the references are pointing to same object but I have created a new ArrayList to add in pq, still this happening.
How does java handle object references while dealing with ArrayLists?
It's all references. Everything. All the way down.
Except primitives. The primitive types are int, long, double, float, byte, short, boolean, and char. That's it. The list is hardcoded and you can't make new primitive types.
So, aside from those, it is all pointers. When you write:
MyFoo foo = new MyFoo();
That's just syntax sugar for 2 separate statements:
MyFoo foo;
foo = new MyFoo();
Imagine the heap is a gigantic whiteboard.
So what's happening here is:
MyFoo foo; This makes a little postit for yourself. This postit is named 'foo', it is yours, you can't hand it to anybody else ('local variable' - hence the name 'local'), and it has just enough room to write a coordinate for that gigantic whiteboard, that's all it can hold. It is blank, for now.
new MyFoo() this goes to the whiteboard, finds some blank space on it anywhere, and writes a box, and then in that box, room for all the fields of your MyFoo class. If any fields are non-primitive, it's just enough room to write coordinates. (Each and every object is its own little box on this whiteboard and could be anywhere on it).
The expression new MyFoo() resolves to the coordinates of where you made that box. You then assign this to foo, so, copy down the location of that box on your little postit.
If you then do:
someMethod(foo);
What that does is: Grabs a new postit, copies those coordinates over to the new postit, and then hands the postit off to someMethod. Specifically:
Even if someMethod changes foo directly (foo =), that is: "They scratch out what was on the postit you gave them and write something new on it", which obviously has no effect whatsoever on your postit.
Once that method is done, they burn the postits. You never get them back. Which is fine, you gave them a copy.
If they FOLLOW the coordinates on that postit and take out their pen and edit the whiteboard, and then later on your follow YOUR postit, you will observe what they changed! . and [] are the dereference operators: That's java-ese for: "Take those coordinates, go over to the whiteboard and find the box, and now we do something to the stuff in the box', whereas = is "edit the postit, scratching out what was there and writing something else in".
With all that context:
obj1.getList() gets you the coordinates to the list object. This list object is simply a big sack of coordinates - of postits. NOT a list of Obj1s! A list of Obj1 references - of coordinates.
new ArrayList<>(that) makes a new arraylist (new box on the whiteboard), that constructor will dutifully copy each and every COORDINATE over. It does not copy each object. It can't, java has no idea how to copy arbitrary objects, and Lists can hold anything, so it doesn't know how.
You then 'poll' the top coordinate from this newly created list. Which is the same coordinate as what obj1.getList() has.
You then go to the whiteboard, following this coordinate (obj2.setField - I see a dot, so, that's 'follow the coords and get out your whiteboard pen'), and modify what is there.
Hopefully that clears up how it works. Keep thinking of that whiteboard. When reasoning about this stuff.
Solutions
The simplest solution is to adopt immutables as much as is reasonable. An immutable object is, effectively, the notion of writing the object in permanent marker. A string is immutable. it has no set or add methods at all. For example, str.toLowerCase() does not lowercase the string that str is pointing at. That method makes a new string instead. It's the equivalent of going to the whiteboard which has "hEllo!" written on it someplace, and then instead of wiping out the E and writing an e in its place (that'd be mutating, and no method in string lets you do this), toLowerCase() just draws a new little box on the whiteboard somewhere and copies the characters over, lowercasing them on the fly. The toLowerCase() call then returns the location of this new box.
If you apply the same ideas to public class Obj1, this problem goes away. So, don't call .setField, call .withField (which makes a clone but with that one field changed) or some such.
If that's not an option, you'd have to deep-clone the list, yes. This is incredibly annoying, because how deep does deep-clone mean? ArrayList itself can't simply deep-clone, you'd have to write it yourself. Something like:
List<Obj1> clone = new ArrayList<>();
for (Obj1 o : original) clone.add(new Obj1(o));
And you'd have to write the Object1(Object1 original) {} constructor yourself, copying each field. And, of course, for each non-primitive field pointing at a mutable object, you'd have to clone that too.
The JavaDoc for ArrayList(Collection<? extends E> c) says:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
It doesn't say "copy".
There's also no "deep copy" mechanism in Java. Even if you use Object.clone (which in general you shouldn't), you will only copy the references inside this object. The references itself will still point to the original contents.
For example:
class Obj {
String a;
int b;
OtherObj c;
}
In memory this will look like this:
[Reference To String a] [Value of int b] [Reference to OtherObj c]
(only primitive types will be stored directly inside an object, everything else is a Class and will be stored as a reference. Even the primitive wrappers like Integer are classes and will be stored as references, but those primitive wrappers are immutable, though you can't change their inner values)
Though if you create a copy of this object, you will get a new memory location for the copy, but that memory location then will contain the same data: [Reference To String a] [Value of int b] [Reference to OtherObj c].
The same happens with ArrayList. In memory it looks like this:
[Reference to Element 1] [Reference to Element 2] [Reference to Element 3] ...
And if you copy that list, you'll get a copy of that part in memory. But all the references will still point to the very same objects.
This all may change with the introduction of Project Valhalla and Value types. But that may still take months or years.
public class example
{
public static void main(String[] args)
{
int[] MyArray = new int[10];
MyArray[1] = 5;
int[] NewArray = MyArray;
NewArray[1] = 10;
System.out.println(MyArray[1]);
}
}
Why does the system print out 10 instead of 5?
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
It seems like whatever changes we made to element in NewArray, MyArray will change along, why?
You aren't changing NewArray. You're changing the array that the value of NewArray refers to. It's like this:
NewArray is a variable (an unconventionally named one, but hey)
The value of NewArray is a reference
The reference refers to an object
It's really, really important to differentiate between variables, references and objects. Don't feel worried that it didn't just come to you immediately - this is a stage a lot of people go through when they first encounter a language like Java.
The values of MyArray and NewArray both refer to the same array, so if you make changes to the array via one variable, you still see the change when you then look at the array via a different variable.
I copy this pattern to initiate like int, string variables but they don't behave like this above, why? thanks guy, I am new to CS programming.
For int, that's a value type - the value of an int variable is the number itself, not a reference to an object.
For String, I suspect you were changing the value of the variable to refer to a different String object - not changing the contents of the String object itself (which you can't - strings are immutable in Java). For example:
String x = "first";
String y = x;
x = "second"; // This doesn't change the value of `y`
I like to think of variables as pieces of paper. For value type variables, the value is just written on the piece of paper:
int i = 10;
is like having a piece of paper with the name i, and a value of 10 on it.
For classes and arrays (which are reference types) the value on the piece of paper isn't the object - it's a way of navigating to the object. A bit like having someone's home address written on a piece of paper.
Suppose you have two pieces of paper with the same address written on them. If you rub one of them out and write a different address, that doesn't change anything about what will happen if someone looks at the other piece of paper and goes to that house. That's like the String example above.
The array example, however, is more like this: I write my home address on two pieces of paper, and give them to Fred and Ginger. Fred reads the address, visits my home, and paints the front door red. (He's modifying the object - my house - without changing his piece of paper at all.) Now if Ginger reads the address on his piece of paper and visits my home, he'll see a red front door.
The reason this happens is because when you say int[] NewArray = MyArray; this is copying the reference of MyArray to NewArray.
This reason you are copying the reference is because you do not call the new operator to instantiate a new array.
So, when you say NewArray[x] it is pointing to the x position in memory of MyArray (and hence the value in memory of MyArray). No new memory is allocated when you do int[] NewArray = MyArray; since the new operator is not called.
It is beacuse when you do =, this makes the new obkect to point to the old one. So any changes made to the new one will reflect in the old one to, as they are the same technically.
You should array.clone to avoid this.
You are not copying it's value. You say:
Java create "MyArray".
Java creates a variable poiting at an object
Java create another array "NewArray" that is the same as MyArray
Java creates a variable poiting at the same object as MyArray
Java change the value of NewArray[1] to 10
Java changes the value on the object it is poiting at, not the variable itself.
Hope you get it.
As a side note, you should use [0] instead of [1]. Arrays start at 0, like everything in programming. So, the array with 10 items you created starts at 0 and ends at 9. Take note of that.
I'm learning deep copy and shallow copy.
If we have two arrays:
int[]arr1={1,2,3,4,5};
int[]arr2={1,2,3,4,5};
Question: Both arrays point to the same references [1][2][3][4][5].
What will happen if I change arr1[2]?Does it changes arr2[2]?
When we pass an array (random array, not necessarily arr1 or arr2) from main into a method the compiler makes a shallow copy of the array to the method, right?
If the Java compiler was re-written to make and send a deep copy of the array data to the method.
What happens to the original array in the main? I think the original array may change according to the method and pass back into the main. I am not sure.
Question: Both arrays point to the same references [1][2][3][4][5].
Not exactly. Your arrays have identical content. That being said, as per your initialization, they data they are using is not shared. Initializing it like so would however:
int[]arr1={1,2,3,4,5};
int[] arr2 = arr1
What will happen if I change arr1[2]?Does it changes arr2[2]?
As per the answer to the above question, no it will not. However, if you were to change your initialization mechanism as per the one I pointed out, it would.
When we pass an array (random array, not necessarily arr1 or arr2)
from main into a method the compiler makes a shallow copy of the array
to the method, right?
Your method will receive a location where to find the array, no copying will be done.
If the Java compiler was re-written to make and send a deep copy of
the array data to the method. What happens to the original array in
the main? I think the original array may change according to the
method and pass back into the main. I am not sure.
If you were to create a deep copy of the array and send it to your method, and your method will work on that copy, then, the original array should stay the same.
Initalization of an array with values will always allocate new memory.
For "int[]arr1 ={1,2,3,4,5};"
The jvm will count the length of the initialization array and allocate the required amount of space in the memory. In this case jvm allocated memory for 5 integers.
when you do "int []arr2={1,2,3,4,5}", the same thing happens again ( jvm allocates memory for another 5 integers).
Thus changing arr1[2] will not reflect arr[2].
arr1[2]=10;
System.out.println(arr2[2]); // this will still print 3
If you wanted arr2 to point to the contents of arr1, you should do this:
int []arr2=arr1;
This would be a shallow copy. This makes an array reference object containing the same value as arr1. Now if you do :
arr1[2]=10;
System.out.println(arr2[2]); //this will print 10.
Now, if you want to do a deep copy of an array( Instead of duplicate initialization as you did), the right command would be:
int arr2[] = Arrays.copyOf(arr1, arr1.length);
This will behave like the first scenario ( your code - Changing arr1 will not affect arr2).
Because you have primitive types, you create independent arrays. To demonstrate deep and shallow copy:
MyObject a = new MyObject("a");
MyObject[] first = new MyObject[] {a};
MyObject[] second = new MyObject[] {a};
a.setName("b");
System.out.println(second[0].getName());
second[0].setName("c");
System.out.println(first[0].getName());
I have encountered a problem in one of my Java projects, which causes bugs.
The problem sounds as following:
I have two arrays. Let's name them firstArray and secondArray. Object in this case is a seperate class created by me. It works, the array can be filled with objects of that type.
Object[] firstArray= new Object[];
Object[] secondArray = new Object[];
Now, when I get an element out of the first array, edit it and then copy it in the second array, the object from the first array gets altered too.
tempObj = firstArray[3];
tempObj.modifySomething();
secondArray[3] = tempObj;
Whenever I do this, the (in this case) 3rd element(actually 4th) of the first array gets the modifications. I don't want this. I want the first Array to remain intact, unmodified, and the objects I have extracted from the first array and then modified should be stored in the second so that the second array is actually the first array after some code has been run.
P.S. Even if I get the element from the first array with Array.get(Array, index) and then modify it, the element still gets modified in the first array.
Hopefully you understood what I wanted to say, and if so, please lend me a hand :)
Thank you!
You're going to have to create a new object.
The problem is the modifySomething call. When you do that, it alters the object on which it's called. So if you've only got one object (even by two names), you can't call modifySomething or they will both change.
When you say secondArray[3] = firstArray[3], you aren't creating a new object: you're just assigning a reference. Going through an intermediate temporary reference doesn't change that.
You'll need code that looks like this:
Object tempObj = firstArray[3].clone();
tempObj.modifySomething();
secondArray[3] = tempObj;
The clone() method must return a new object divorced from the original but having identical properties.
When you retrieve an element from your array, you have a reference to it. So if you modify it, the modification are shered through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new Object and use its constructor to initialize its fields.
The object extracted from the first array needs to be cloned to create a new instance that is seperate. Otherwise the modification will affect the object in the first array as it is the same object.
When you retrieve an element from your array, you get a reference to it. So if you modify it, the modification are shared through all the object's references.
In order to leave it intact, you should use some method like Object.clone() or create a new method which take in input your retrieved object and return a new one alike.
In Java, when you do this secondArray[3] = tempObj;, you actually put the reference to the array, not the real object
So firstArray[3] and secondArray[3] point to the same real object
What you need to do is to create a new object that is identical to your original object, and put the reference of the new object to your secondArray
It might worth to point out that default clone() function only does a shallow copy, so if you have mutable objects in your object's fields, it might cause some problems. Take a look at this article about how to do a deep copy
Hey people i have this structure for the search tree
class State
{
//CLASS STATE
int value;
char[][] state; //the game Grid
State child[]; // children of current state, maximum is 8
State(char[][] src)
{
state=src;
child=new State[8];
}
this is the root node definition
State rootNode = new State(currentGrid);
rootNode.value=-1;
int v =maxValue(rootNode,depth);
after the end of recursion in the max value function the array in rootNode should not be edited since its the the first state but when i Display it i get an array filled with stuff which means that the rootNode.state passed by reference to the max value function :(
//i am trying to implement MiniMax Algorithm.
If you don't want objects that are passed as parameters to be changed, pass in a copy (or make a copy of the parameter inside the method).
Note that char[][] means you have an array of char arrays, i.e. you are working with objects and if you copy the first level you still might have a reference to the second.
Thus you might have to loop through the first level/dimension and copy all the arrays in there, like this:
char target[][] = new char[state.length][0];
for( int i = 0; i < state.length; ++i ) {
target[i] = Arrays.copyOf(state[i], state[i].length);
}
If you need, you can easily create a copy of the array through Arrays.copyOf
You can also create a deep copy. How to do this has been answered here: How to deep copy an irregular 2D array
Yes, Java passes references to arrays and not the array as a value. So if you give a reference to your internal state away, the receiver can change it and the change is "visible" in the source (in fact: it's only one array that has been changed and all reference holders will see the change).
Quick fix/solution: clone your state array and pass a reference to this clone instead of the original. This will keep your internal root state unmodified.