java clone() with array - java

i am trying this in my copy constructor
protected int forca;
protected Spell []feitico;
public Picareta(final Picareta rValue)
{
super((Ferramenta)rValue);
this.forca=rValue.forca;
this.feitico=rValue.feitico.clone();
}
but feitico has the same references instead of cloning the objects in the array
do i really need to clone every element inside the array , or is my clone() for Spell wrong ?
public Spell clone() throws CloneNotSupportedException
{
super.clone();
Spell temp= new Spell(this);
return temp;
}
or is this way the best(compact) way to make it ?
public Picareta(final Picareta rValue)
{
super((Ferramenta)rValue);
this.forca=rValue.forca;
this.feitico=new Spell[rValue.feitico.length];
for (int i=0;i<rValue.feitico.length;i++)
this.feitico[i]=new Spell(rValue.feitico[i]);
}

The method .clone() on an array object will clone the array. That does not clone other objects, namely the objects referred to by elements in the array.
What you are asking about is a "deep copy" or "deep clone". After creating a new array to hold the new objects, then you need to iterate through the old array and clone each of the objects referred to there:
this.feitico = new Spell[rValue.feitico.length];
for (int i = 0; i < this.feitico.length ; i += 1)
{
this.feitico[i] = rValue.feitico[i].clone();
}

clone for arrays of reference type is only a shallow copy, so yes you will need to copy every element inside the array.
You already have a copy constructor for Spell, so this is not too hard.
Using Java 8, there is a nice way to copy a Spell[]:
this.feitico = Arrays.stream(rValue.feitico).map(Spell::new).toArray(Spell[]::new);
With Java 7 and below, your way cannot be improved.

Related

How do I make a copy of an Array, which I can return in a public method?

Basically I got told that I shouldn't have public methods returning Arrays for "future" security purposes. Instead they should be private, and if I wanna return an Array it would have to be some kind of copy in another method.
This is how it looks now..
public Object[] ownedObject() {
return objectArr;
}
If I make this private the class that needs it doesn't recognize the method above.
Thing is I need to use the contents in that Array in said, other class, and the total project, as I have it right now with 5 different classes, works (with the returning Array-methods set to Public and not private).
As you are concerned with security aspect of this problem you might want to distinguish between shallow copy and deep copy of the array. If your array contains mutable objects you probably need a deep copy of every single element in the array to ensure that state is not leaking from your object.
Assuming that you array is of type MyType with a copy constructor:
public MyType[] ownedObject() {
MyType[] copyArr = new MyType[objectArr.lenght];
for (int i = 0; i < objectArr.lenght; i++) {
copyArr[i] = new MyType(objectArr[i]);
}
return copyArr;
}
There are also other ways to deep copy an object.

How to prevent changing the value of array or object

I am a beginner in Java. When developing a program, I created an object with a constructor with variables as arguments. But when I change the value of the variable after creating the object, my object has the second value instead of the first one. I don't want my object to change the value. What do I do?
public class Person {
public Person(int[] arrayTest) {
this.arrayTest = arrayTest;
}
public int[] getArray() {
return this.arrayTest;
}
public boolean canHaveAsArray(int[] arrayTest) {
return true;
}
private int[] arrayTest = new int[2];
public static void main(String[] args) {
int[] array = new int[] {5, 10};
Person obj1 = new Person(array);
array[0] = 20;
System.out.println(Arrays.toString(obj1.getArray()));
}
}
My output should be [5, 10], but instead, I am getting [20,10]. I need to get [5,10] even when I change an element of the array as shown above. What should I do?
If you pass the original array to the constructor of Person, you are passing the reference to the original array. So any change in arrayTest inside Person instance will reflect in original array(int[] array) and vice-versa.
If you don't want to change the value of elements of original array in Person instance then you have two options:
You can modify the code in Person constructor to create a copy of original array using java.util.Arrays.copyOf method and then use that copy:
public Person(int[] arrayTest) {
this.arrayTest = java.util.Arrays.copyOf(arrayTest, arrayTest.length);
}
Don't pass the original array to constructor, instead just send a copy of original array:
Person obj1 = new Person(java.util.Arrays.copyOf(array, array.length));
However, I would prefer first approach.
If you would like to prevent the value of variable which is of primitive type, you can do so using final keyword. Eg:
private final int test = 1;
To prevent changing the value inside an object you can mark the fields as final. A final keyword in declaration of object instance means the variable can't be reassigned and doesn't guarantee that the object state won't change if the reference to that object is shared. To prevent changing the state of a particular object, you should mark it's field as final.
There is no such thing as immutable (unchangeable) array in Java. The Java language does not support this. As JLS 4.12.4 states:
If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. This applies also to arrays, because arrays are objects; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array.
The JVM spec doesn't support an immutable array type either. You can't solve this at the language level. The only way to avoid changes to an array is to not share the reference to the array with other code that might change it.
In your example, you have what is known as a leaky abstraction. You are passing an array to your Person class, and the caller is keeping a reference to that array so that it can change it. To solve this, you can:
copy the array, and pass a reference to the copy, or
have the constructor (or a setter for the array attribute) make the copy.
(See answer https://stackoverflow.com/a/55428214/139985 for example code.)
The second alternative is preferable from an OO perspective. The Person class should be responsible for preserving its own internal state from interference ... if that is your design requirement. It should not rely on the caller to do this. (Even if the caller is technically part of the same class as is the case here.)
There is no unmodifiable array, but you can make an unmodifiable list:
List<Integer> list = List.of(5, 10);
You will have to change your code to use lists instead of arrays, but this is generally preferable anyway.
If you already have an array of a non-primitive type, you can wrap it in an unmodifiable list, like so:
List<Integer> list = Collections.unmodifiableList(Arrays.asList(array));
However, while you can't change the list directly, changing the array will change the list. Moreover, this won't work on int[], but only on subclasses of Object[].
In Java, objects/arrays are manipulated through reference variables#
When a function is invoked with arrays as their arguments, only a reference to the array is passed. Therefore, when you mutate array array, the arrayTest field also get mutated as they are referring to the same address
To override this behavior, you can create a copy of the array in your constructor using Object.clone() method like:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone();
}
# Source: Wikipedia
Instead of passing a copy of the array to the object, as others have suggested, I would recommend that the Person object's constructor should create a copy. Which means instead of,
this.arrayTest = arrayTest;
It should be
this.arrayTest = Arrays.copyOf(arrayTest, arrayTest.length);
This would allow the object to be defensive against malicious code trying to modify arrays after construction and validation by constructor. In fact most IDEs have analysis tools which will give you a warning against saving array reference.
As others have already pointed out: The array is passed as a reference to the Person. So changes that are later done to the array will be visible to the Person object. But that's only one half of the problem: You are not only passing a reference to the array to the constructor of the Person, you are also returning a reference from the getArray method.
Generally speaking, and as StephenC already pointed out in his answer: One important aspect of Object-Oriented design is to properly manage the state space of objects. It should not be possible for users of a class to bring an object into any form of "inconsistent state".
And this is difficult with plain primitive arrays. Consider the following pseudocode, referring to the class that you posted:
int originalArray[] = new int[2];
originalArray[0] = 12;
originalArray[1] = 34;
Person person = new Person(originalArray);
int arrayFromPerson[] = person.getArray();
originalArray[0] = -666; // Modify the original array
System.out.println(arrayFromPerson[0]) // Prints -666 - this is unexpected!
arrayFromPerson[1] = 12345678; // Modify the array from the person
System.out.println(originalArray[1]) // Prints 12345678 - this is unexpected!
Nobody knows who has a reference to the array, and nobody can verify or track that the contents of the array is not changed in any way. How critical this is becomes more obvious when you anticipate that the Person object will be used at different places, possibly even by multiple threads.
Plain primitive arrays in Java do have their justification. But when they appear in the interface of a class (that is, in its public methods), they should be view with scrutiny.
In order to be absolutely sure that nobody can interfere with the array that is stored in the Person object, you'd have to create defensive copies everywhere:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone(); // Store a clone of the array
}
public int[] getArray() {
return this.arrayTest.clone(); // Return a clone of the array
}
But this may be cumbersome. A more object-oriented solution could be to expose a "read-only view" on the state that is represented with the array. For example:
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone(); // Store a clone of the array
}
public int getArrayLength() {
return this.arrayTest.length;
}
public int getArrayElement(int index) {
return this.arrayTest[index];
}
(Of course, in practice, you'd name the methods accordingly, depending on what the array actually represents. For example, if it's the ages of the children of the person, you'd call the methods getNumChildren() and getAgeOfChild(int i) or so...)
Another option how this can be solved is to expose an (unmodifiable) List view on the array. This can, for example, be done with the asUnmodifiableList method that is shown in this answer.
as you are beginner in java you write following code in constructor but it is better to use clone method as marco13 and rv 7 already explained
and as sourabh bhat explained we can also use Arrays class copyof
the idea behind all of above logic is simple don't pass referance of current object but create clone of object and pass that clone or just copy each content of the object
public Person(int[] arrayTest) {
for (int i = 0; i <this.arrayTest.length; i++) {
this.arrayTest[i]=arrayTest[i];
}
}
Here is what happens in memory:
Program: Stack memory: Heap memory:
int[] array = new int[] {5, 10}; array -> 0x77a89 0x77a89 {5, 10}
Person obj1 = new Person(array); obj1.arrayTest -> 0x77a89 No change
array[0] = 20; 0x77a89 {20, 10}
As you can see stack memory holds only the address of the object which gets created in the heap memory. So when you change the arrays value it automatically changes in the Person obj1 object as well.
To fix this you need to create a new Object in memory so that the actual Objects value is copied. To do this we can:
[1] Use the clone property of array.
public Person(int[] arrayTest) {
this.arrayTest = arrayTest.clone();
}
[2] Or we can create our own clone.
public Person(int[] arrayTest){
if (arrayTest == null){
this.arrayTest = null;
} else {
int[] copyArray = new int[arrayTest.length];
for(int i=0; i<arrayTest.length; i++) {
copyArray[i] = arrayTest[i]
}
this.arrayTest = copyArray;
}
}
Either way a new Object is created in memory and this prevents the object from being shared.
Edit 5/5/19: Source code added
As most answers point out, there is no immutable array of primitives in Java. So you have to do some tricks.
Pure Java: Make defensive copies. Most answers show how to store a copy of the array that is received as a parameter in the constructor. But only one answer mentions that you also have to return a copy of the internal array with getArray().
public class Person {
final private int[] arrayTest;
public Person(int[] arrayTest) {
this.arrayTest = java.util.Arrays.copyOf(arrayTest, arrayTest.length);
}
public int[] getArray() {
return java.util.Arrays.copyOf(arrayTest, arrayTest.length);;
}
}
Other internal representation: Store the array as a (mutable) ArrayList, which is based on an array and should have best performance. You have to convert from array to List in the constructor and from List to array in getArray(). There is no need to use Collections.unmodifiableList() (or Guavas ImmutableList<>) as long as you write no method that could modify the List because no one will have access to the List.
public class Person {
final private List<Integer> arrayTest;
public Person(int[] arrayTest) {
this.arrayTest = new ArrayList<>(Arrays.asList(arrayTest));
}
public int[] getArray() {
return this.arrayTest.stream().mapToInt(Integer::valueOf).toArray;
}
}
Let other people do the job. Google AutoValue auto-generates immutable classes. And provides equals(), hashCode() and toString(). Easy to use. My favorite solution.
import com.google.auto.value.AutoValue;
#AutoValue
public abstract class Person {
public static create(int[] arrayTest) {
return new AutoValue_Person(int[] arrayTest);
}
public abstract int[] getArray() {}
}

Bug in using Object.clone()

I have the next scenario:
I define an int[][] variable in my main class. int[][] matrix1 = new int[10][10] and i give it some values. I then call a method and i send this variable as a parameter to that method. Being an object it sends is by reference not by value, so inside the method, because i have to change the values contained by matrix1 but not affect the object after it returns from the method, i make a clone of it like so:
private void myMethod( int[][] matrix1 )
{
int[][] matrix1Clone = matrix1.clone();
//And next i do some changes to matrix1Clone
......
}
But the problem is that the changes i do to matrix1Clone also happen in matrix1. So it hasn't really created a clone of matrix1 object, but both variables point to the same object.
Why is this? I can't seem to figure it out. Why doesn't clone method work?
If you need more info, please ask. But i'm afraid this is about it, can't really give you more, but maybe i could try.
I might be missing something, but i can't figure out what...
Thanks.
EDIT
Sorry, made a typo. It's late hre and i'm tired. I'm using clone method indeed, that's why i'm confused as it's not working :(.
Try clone it using clone() http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#clone%28%29
private void myMethod( int[][] matrix1 )
{
int[][] matrix1Clone = matrix1.clone();
}
or, copy all of the values using a loop
EDIT: Api for clone() says it should return a copy of the object, but behavior might be different depending on which object's beeing cloned. Try iterating over the array as an alternative. Since it's a 2d array, you need a nested loop:
for(int i=0; i<old.length; i++)
for(int j=0; j<old[i].length; j++)
old[i][j]=copy[i][j];
where old is the "original array" and copy is the copy
You are giving matrix1Clone same reference as matrix1. If you change matrix1Clone then matrix1 changes too.
You can copy your array with iterating over the source array:
public static int[][] clone2DArray(int[][] array) {
int rows = array.length;
//clone the 'shallow' structure of array
int[][] newArray = array.clone();
//clone the 'deep' structure of array
for(int row = 0; row < rows; row++){
newArray[row] = array[row].clone();
}
return newArray;
}
Actually, arrays have no values but pointers towards object or primitive datatypes. If you want a detailed answer, you should read my commentary here: Java is NEVER pass-by-reference, right?...right? or here: In Java, what is a shallow copy?
So, as arrays are pointers, what happens if you clone a pointer with pointers in it? At first, the pointers are copied for real, but these pointers only point toward other object which aren't cloned. So if you want to clone, I suggest not using arrays but "harder" data structures: classes. Another possibility would to never store an array within an array...like I use arrays only for containers!
But I can't give you details about Java multidimensional generics, as I never deal with them, not only because of their possible inconsistency because they are arrays (they're violating some OO principles anyway and make code looking ugly).
EDIT
I was running a few tests how the clone method works for arrays inside a class, what the problem is and which workarounds we have.
First the test data structure:
public class Foobar implements Cloneable {
String[] array;
public Foobar() {
this.array = new String[10];
}
public String getValue(){
return array[0];
}
public String[] getArray(){
return array;
}
public void setArray(String[] array){
this.array = array;
}
#Override
public Object clone(){
try{
Foobar foobar = (Foobar) super.clone();
foobar.setArray(array);
return foobar;
}
catch(Exception e){
return null;
}
}
}
Now the controller:
String[] array = new String[10];
array[0] = "111";
Foobar foo1 = new Foobar();
foo1.setArray(array);
Foobar foo2 = foo1; //Alternation: Foobar foo2 = (Foobar) foo1.clone();
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
array[0] = "999";
System.out.println("Instance: "+foo1.getArray()+" with value: "+foo1.getValue());
System.out.println("Instance: "+foo2.getArray()+" with value: "+foo2.getValue());
The test results will always look like that - no matter if I use = or clone():
Instance: [Ljava.lang.String;#42e816 with value: 111
Instance: [Ljava.lang.String;#42e816 with value: 111
Instance: [Ljava.lang.String;#42e816 with value: 999
Instance: [Ljava.lang.String;#42e816 with value: 999
This is not good!!
So what is the workaround? I suggest doing this in every data structure class:
public class Foobar implements Serializable {
//any class variables...it doesn't matter which!
public Foobar() {
//do initialisation here...it doesn't matter what you do!
}
public Foobar copy(){
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Foobar foobar = (Foobar) ois.readObject();
return foobar;
}
catch(Exception e){
return null;
}
}
}
So you will get a full copy by implementing just one line of code:
Foobar foo2 = foo1.copy(); //nice and easy!!
The advantage of this solution: It's usually enough to implement the interface Serializable to make a class "copyable". And if not, you can solve any issues by reading what is written in the Serializable Javadoc!
Even more: It doesn't matter what kind of objects are in the class you want to make "copyable", so you don't need to spend any more time on this issue. After all, above code is the simpliest and fastest solution deeply embedded in Java ever since and uses only RAM! (thanks to ByteArrayOutputStream)
Enjoy!
UPDATE: Note that you only need to use an object's copy if you want a temporary stack or if you are dealing with threads (in general: if you need to have objects fully independent from each other). Otherwise you shouldn't make any copy at all! Also if you write some data into a file or a socket, you don't need a copy. Even more I suggest to implement the copy method only when it's really used: for data structures (model). So be careful by using this mighty method (otherwise it could slow down your app, or even fill up the Java VM storage if you make millions of copies with no reason, this would cause a stackoverflow indeed :o).
EDIT
I was working a bit more on the this issue. Because I suddenly found out, that there is a public clone() method of "primitive" arrays that aren't in the Java API !! (a "easter egg" from SUN for arrays like String[] or int[] ;-)
And as I use real arrays as the basic data structure of Foobar (not ArrayLists!), I can change the clone method (of above class) like this:
#Override
public Object clone(){
try{
Foobar foobar = (Foobar) super.clone();
String[] arrayClone = array.clone(); //who thought that this is possible?!
foobar.setArray(arrayClone);
return foobar;
}
catch(Exception e){
return null;
}
}
And now we get this result right out of the box:
Instance: [Ljava.lang.String;#42e816 with value: 111
Instance: [Ljava.lang.String;#9304b1 with value: 111
Instance: [Ljava.lang.String;#42e816 with value: 999
Instance: [Ljava.lang.String;#9304b1 with value: 111
Problem solved with "double-nested" objects!!! As you can see, the clones have different objects independently from the original...therefore foo1.equals(foo2)) will be false!
Solution: In the clone method of a class, you need to clone all its class variables, too! (But if some class variables are ArrayLists or more-dimensional arrays, even this solution won't work!)
Finally, what is the real issue? The class ArrayList doesn't clone it's arrays, it only calls the method copyOf in the class Array, which is harmful. So never use the clone method of the class ArrayList, and never inherit any class from ArrayList because its clone method won't work! (It works only if the class ArrayList only contains primitives and no objects...otherwise just use the easy ByteArray solution above!).
Note that with more-dimension arrays like Object[][] you always need to implement the ByteArray solution above, they can't be cloned! And if your array is huge, it may take a while and need some RAM, too.
Now you are a cloning expert! :-D

Deep copy of 2D array with all elements

I am making a basic game using a 2D array (4x4) in which the elements (of object type with ints 1 to 16) must be switched around to reach a particular goal state, this state must be compared with the current state, hence the need for copying.
So far I have:
public void cloneArray() throws CloneNotSupportedException
{
ClassName copy = (ClassName)super.clone();
copy.tiles = (Tile[][]) tiles.clone();
}
Does this appear to be right, or am I missing something out?
You'll need to go one step further and do like so :
ClassName copy = (ClassName)super.clone();
copy.tiles = (Tile[][]) tiles.clone();
for(int i = 0; i < copy.tiles.length; i++) {
copy.tiles[i] = (Tile[]) tiles[i].clone();
}
The reason is that clone makes a shallow copy of the top-level array, which is holding references to other arrays.

Simulating pass by reference for an array reference (i.e. a reference to a reference) in Java

I was wondering, in java, is it possible to in anyway, simulate pass by reference for an array? Yes, I know the language doesn't support it, but is there anyway I can do it. Say, for example, I want to create a method that reverses the order of all the elements in an array. (I know that this code snippet isn't the best example, as there is a better algorithms to do this, but this is a good example of the type of thing I want to do for more complex problems).
Currently, I need to make a class like this:
public static void reverse(Object[] arr) {
Object[] tmpArr = new Object[arr.length];
count = arr.length - 1;
for(Object i : arr)
tmpArr[count--] = i;
// I would like to do arr = tmpArr, but that will only make the shallow
// reference tmpArr, I would like to actually change the pointer they passed in
// Not just the values in the array, so I have to do this:
for(Object i : tmpArr)
arr[count++] = i;
return;
}
Yes, I know that I could just swap the values until I get to the middle, and it would be much more efficient, but for other, more complex purposes, is there anyway that I can manipulate the actual pointer?
Again, thank you.
is there anyway that I can manipulate the actual pointer?
Java does not pass by reference, so you can't directly manipulate the original pointer. As you've found out, Java passes everything by value. You can't pass a reference to an array object, and expect a method to modify the original reference to point to another array object.
You can, of course:
Modify elements of the referred array object (ala java.util.Arrays.sort)
Pass a reference to an object with a settable field (e.g. Throwable has a setStackTrace)
return the new reference instead (ala java.util.Arrays.copyOf)
Well, you can explicitly pass an object that contains a reference. java.util.concurrent.atomic.AtomicReference is ready out of the box, although it does come with volatile semantics that you probably don't want. Some people use single element arrays to returns values from anonymous inner classes (although that doesn't seem a great idea to me).
This method reverses the Array's elements in place. The caller sees the changes. (In Java everything is passed by value, including object references.)
public static void reverse(Object[] arr) {
for ( int i = 0, j = arr.length - 1; i < j; i++, j-- ) {
Object temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
In Java Object reference is passed by value.
So if you looking for something like
function referenceCheck()
{
int[] array = new int[]{10, 20, 30};
reassignArray(&array);
//Now array should contain 1,2,3,4,5
}
function reassignArray(int **array)
{
int *array = new int[] { 1, 2, 3, 4, 5};
}
Then its not possible in Java by any direct means.
If we need to change only the values stored in an array, then we can do it since object reference is passed by value.
You want to pass a reference to the array reference. In that case you just have to either create a class to hold the reference and pass a reference to that class or just pass a 1-element array of the type being passed. Then you'd be passing either an object holding the array or an array whose only element contains the array you want to operate on.

Categories

Resources