int[][] array = new int[][] {...}
int[][] clone = array.clone();
I naively expected this to work. But it didn't - it cloned only the first dimension, and I had to go and clone the other dimension manually if I wanted a true clone. Note: the contents were properly copied. But when I changed clone[0][1], it reflected in array[0][1]
And while .clone() is known to perform a shallow clone, int[][] looks like a single object (if we don't know its internal implementation, at least)
Why is that behaviour chosen? Isn't int[][] referencing an array object, rather than just the first dimension of the array? And in what scenarios is cloning only the first dimension the desired behaviour?
Why is that behaviour chosen?
Consistency, most likely.
As you say, int[][] references an array object. It just so happens that the contents of each array element is another array, but that's just a detail. Java clones all arrays identically, and since the elements can be of any type it can't guarantee to perform a deep copy.
Hence clone() for arrays performs a shallow copy, so only the first dimension is cloned.
(In general it doesn't seem that there's a single "best" or "obvious" answer to the question of whether a clone implies deep or shallow copies. What the developer wants will depend on how each field is being used by the application, so a one-size-fits-all approach will naturally have limitations.)
This behavior is demonstrated because there is no true multi dimensional array.
Java achieves multiple dimensions by making arrays of arrays. Which means:
int[][] is actually Array<Array<int>>
Hence the clone would only copy the first dimension.
If you were trying with a 3 dimensional array, you would need to clone thrice.
The clone method is a so called shallow copy (see another stackoverflow answer on the clone method), which means that all the elements are copied by reference.
To get to what you want (also called deep cloning) you can either copy every single array yourself using the Arrays.copy recursively, so every (sub-)array you find will get a deep-clone, or check this stackoverflow answer on deep cloning.
Happy hacking :-)
I am actually not able to replicate the behavior you have mentioned. I can see some answers mentioning shallow copy as the root cause of the issue. Correct me if I am wrong, shallow copy just means that instead of copy of an object while cloning, we will get copy of the reference. A good explanation can be found here In Java, what is a shallow copy?
In this case shallow copy will only make sure that changes in original array get reflected in the cloned array but will not stop anything from being copied.
int[][] array = new int[][] {{1,2,3},{4,5,6}, {7,8,9}};
int[][] clone = array.clone();
//Try this to see magic of shallow copy
//array[2][1]=11;
for(int i=0;i<array.length;i++)
for(int j=0;j<array[i].length;j++)
System.out.println("array["+i+"]["+j+"]"+array[i][j]);
for(int i=0;i<clone.length;i++)
for(int j=0;j<clone[i].length;j++)
System.out.println("clone["+i+"]["+j+"]"+clone[i][j]);
For me the cloning is done perfectly, that is both arrays have same contents. The only reason I can think of for getting the issue that cloned array will not show some information is that we have actually modified original array after the cloning (shallow copy comes into play then).
BTW I used Java 1.6, I hope that is not an issue.
Edit: If we just need to understand why their is a shallow copy instead of deep copy of a multidimensional array. Let's look at 2 facts
While cloning, Objects always gets cloned as shallow copy (copy of reference of the object), only native types get a real copy. In Java, what is a shallow copy?
An array in java is actually an object Is an array an object in java
Now combining 1 and 2, we know that multidimensional array in Java is just an object, which has reference of other array objects.
Something like ArrayObj->{ArrayObj, ArrayObj, ArrayObj};
And because we have Objects inside objects (composition), we are supposed to get a shallow copy as per Java cloning rule.
Related
I'm working on some code and trying to figure out how to copy an object reference to another object. I keep seeing the clone() method used, but I've read it's flawed and the class I'm wanting to copy is already implementing serializable. So one question I have is about the difference between using '=' and the clone method - My understanding is that both of these are shallow copies so they should work the same, but if that's true, then what is the benefit of having a method for this?
The code I'm working on has 2 arrays of objects - both the same type of object, all objects in both arrays are initially null, and I assign the values of array B to equal array A.
As the code progresses objects in array A are initialized and values are assigned to the variables of the objects in array A.
At the end of the code though, all objects in array B are still null.
Do I have the concept wrong here?
If the concept isn't wrong I assume it's just something I'm overlooking in my code.
Any help is appreciated.
I'll make my comment an answer:
Your question is comparing apples to oranges, they are so completely different that they can't be compared. = assigns a reference, that's it. Clone creates a completely new object, one whose state should be the same as the cloned object, but again it is a completely different object/reference. As an aside, there are deep and shallow clones, and so the composite fields of shallow copied clones may be identical, but that's the subject of another question.
When you use =, you copy the reference of the object (in memory). When using .clone(), you create a new object.
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
I noticed that in Java that when you pass an array into a function, it modifies the original array. I am trying to implement the backtracking method that uses recursion and I want each call to it to have its own array copying the contents of the array passed in.
For example, say I have an original array and I go through a loop that calls the function. I want each call to have an array that contains everything from the original array, but anything it modifies stays within itself, not modifying the original array. Is this possible?
If there's a solution, would it be possible for arraylists also?
You can use Arrays.copyOf methods.
Probably the fastest way to do this in Java will be the System.arraycopy method documented here. It's a native method and is generally as fast as you're going to get.
In certain cases you could try a copy-on-write approach which might help if you are not really modifying the entire array.
java.util.Calendar.clone() returns "...a new Calendar with the same properties" and returns "a shallow copy of this Calendar".
This does not appear to be a shallow copy as answered here on SO. That question is tagged language-agnostic, Java does not seem to follow the language agnostic definition. As I step through the code I notice that the structure and the elements are copied to this new object, more than the language agnostic structure only.
In Java, what is a shallow copy?
How does it differ from a Java deep copy (if that exists)?
A shallow copy just copies the values of the references in the class. A deep copy copies the values. given:
class Foo {
private Bar myBar;
...
public Foo shallowCopy() {
Foo newFoo = new Foo();
newFoo.myBar = myBar;
return newFoo;
}
public Foo deepCopy() {
Foo newFoo = new Foo();
newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ...
return newFoo;
}
}
Foo myFoo = new Foo();
Foo sFoo = myFoo.shallowCopy();
Foo dFoo = myFoo.deepCopy();
myFoo.myBar == sFoo.myBar => true
myFoo.myBar.equals(sFoo.myBar) => true
myFoo.myBar == dFoo.myBar => **false**
myFoo.myBar.equals(dFoo.myBar) => true
In this case the shallow copy has the same reference (==) and the deep copy only has an equivalent reference (.equals()).
If a change is made to the value of a shallowly copied reference, then the copy reflects that change because it shares the same reference. If a change is made to the value of a deeply copied reference, then the copy does not reflect that change because it does not share the same reference.
C-ism
int a = 10; //init
int& b = a; //shallow - copies REFERENCE
int c = a; //deep - copies VALUE
++a;
Result:
a is 11
*b is 11
c is 10
Shallow copy is a just a set of pointers to the same memory locations. Actually it does not create a real copy so the memory usage is lower.
In a case of a deep copy, an exact copy of the memory segment is created and pointers are set to new memory locations. So theoritically the memory consumption should be twice in this case.
A shallow copy is a copy of the reference pointer to the object, whereas a deep copy is a copy of the object itself. In Java, objects are kept in the background, what you normally interact with when dealing with the objects is the pointers. The variable names point to the memory space of the object. A shallow copy is made when you set one variable equal to another like so:
Object B = A;
A deep copy could be made by getting the properties of object A and putting them in a new object B.
Object B = new Object(A.getProperty1(), A.getProperty2()...);
This affects program behavior in that if you make a shallow copy and perform a task on it, that affects all shallow copies of the object. If you make a change to a deep copy, only that copy is affected. I hope this is detailed enough for you.
The 1.6 docs document Calendar.clone as "Creates and returns a copy of this object." A literal shallow copy as specified by Object.clone wouldn't make any sense. Java uses the term "shallow copy" in a fairly typical sense.
It appears to be a mistake in the documentation. I don't see how anything that Android's Calendar.clone method does meets the typical definition (in Java or otherwise) of a "shallow copy".
SHALLOW COPY is PASS-BY-REFERENCE ...
DEEP COPY is PASS-BY-VALUE …
The context is different, but the process is exactly the same. First remember that in Java method calling, primitives are passed by value, while objects are passed by reference (in other languages, objects may also be passed by value). Now, in Java, when the caller passes a primitive to the called method, the called method simply clones it as a new local variable, which is a deep copy. While if an object is passed, the called method will only make a new local reference to the same object, which is shallow copy. If you understand calling, you understand deep/shallow copy, & vice versa.
Where are you getting this documentation?
The official Java 6 docs on java.sun.com simply have Calendar.clone() returning a copy of the object. No mention of shallow.
More generally, a shallow copy in Java is one where you get a new object reference but the new object holds (directly or indirectly) references to data in the original.
For example:
class MyClass{
private List<Integer> innerList;
public MyClass(List<Integer> list) { innerList = list; }
//Some code...
public Object clone(){
return new MyClass(innerList);
}
}
returns a shallow copy in its clone().
First of all, the Javadoc of ArrayList is somewhat wrong if we are talking about one-dimensional arrays, as it uses the method copyOf in Arrays. So clone() gives back a one-dimensional copy, at least since 1.5 (I didn't test further)! So that's what "shallow" means in Java: one-dimensional
You can read more here: http://www.javapractices.com/topic/TopicAction.do?Id=3. So clone() is no shallow copy! If you want a real shallow copy of a one-dimensional array, just reference it:
Array a = new Array();
Array b = a; //a is only a shallow copy, nice for synchronisation
Arrays in Java are tricky, also because Java does pass-by-value, but the values of arrays are only their pointers! In the other hand this allows us to synchronize the objects, which is a great thing. Still, there are some problems if you use arrays within arrays (or ArrayLists), because a clone() of the container array (or ArrayList) won't copy their values, only their references! So you simply shouldn't put any arrays into an array, you should only deal with objects in an array!
And Javadoc is difficult to understand sometimes, so give testing a try...
Have fun!
A shallow copy just copies the object reference into the target reference. It does not create a new object on the heap.
By default, Java does shallow cloning using clone() function.
To get a new object on the heap, one has to perform deep cloning which can be implemented by Serialization and De-serialization.
In a shallow copy,the clone object has a copy of primitive values but the object references refer to the same objects as the original copy.
Shallow Copies have a significant drawback, cloned object and original copy refer to the same address object. Any change that cloned object makes in address object will also be reflected in original copy, which is an unwanted behaviour. What we really wanted is two separate copies of user object. Deep copying comes to our rescue for this kind of situation.
Deep copying clones not just the primitive values, it also creates copies of object references.
You can have a look at working example on this at here :https://codingninjaonline.com/2017/11/09/deep-vs-shallow-copy/
Shallow Copy : In this cloning any changes to Cloned Object is reflected to Original Object also.
Deep Copy : In this cloning a separate cloned memory is alloted which means any changes to cloned object will not be reflected to original object.