Java class copying and arrays - java

I am having some issues withs objects within an array working as one object rather than seperately as intended. For example
boardArray = new object[4];
workingBoardArray = new object[4];
boardArray[0] = new board(boardA);
boardArray[1] = new board(boardB);
boardArray[2] = new board(boardC);
boardArray[3] = new board(boardD);
int selectedBoard = selectBoard(boardArray);
workingBoardArray[0] = boardArray[selectedBoard];
workingBoardArray[1] = boardArray[selectedBoard];
workingBoardArray[2] = boardArray[selectedBoard];
workingBoardArray[3] = boardArray[selectedBoard];
workingBoard[0].moveUp();
workingBoard[1].moveRight();
workingBoard[2].moveDown();
workingBoard[3].moveLeft();
This code creates a set of 4 boards, finds the desired board, copies that board into the working board array and then shifts each working board in a new direction. The problem is that the boards all act together. So if I do moveUp() on workingBoard[0], workingBoard[1] is also moved up. Is there any way around this, I feel like I am missing some fundamental understand or a really silly mistake.
I also tried using a copy constructer like
workingBoard[0] = new Board(boardArray[selectedBoard].getBoard);
Which retrieves all essential board information and creates a new board with it, but that doesnt seem to affect anything. Any help would be great

Look at this code:
int selectedBoard = selectBoard(boardArray);
workingBoardArray[0] = boardArray[selectedBoard];
workingBoardArray[1] = boardArray[selectedBoard];
workingBoardArray[2] = boardArray[selectedBoard];
workingBoardArray[3] = boardArray[selectedBoard];
That's setting all four array elements to be references to the same object. So yes, when you modify that object by calling moveUp() or whatever, that change will be visible via all the elements in the array.
It sounds like you may want to create a copy of the board each time. Depending on what your board type (which should be called Board to follow naming conventions) does, you may want to just implement Cloneable (quite possibly overriding the clone() method) or provide some other sort of copying operation.
Are you aware of the difference between a reference and an object in Java, and that the array only contains references, not objects? (Likewise any variable value will only be a reference rather than on object.) It's really important to understand how objects work in Java. For example:
StringBuilder a = new StringBuilder();
StringBuilder b = a;
a.append("Foo");
System.out.println(b); // Still prints "Foo"
Here we've got one StringBuilder object, even though there are two variables (a and b) whose values refer to that same object.

... copies that board into the working board array and then shifts each working board in a new direction.
Actually you don't copy the board. There is only one board instance which is referenced four times from workingBoardArray. To make copies of the board you have either to implement the clone method or provide a custom copy method.
For example if you implement the clone method you could write:
workingBoardArray[0] = boardArray[selectedBoard].clone();

Related

Undesrstanding clone method for arrays

I've learnt that for arrays the clone method is well-behaved and we can use it. But I thought that the type of the elemetns the arrays hold should have implemented Cloneable interface. Let me provide some example:
public class test {
public static void main(String[] args){
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = arr_t.clone();
an_arr[0]= new Test(5);
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //10
}
public static class Test{
public int test;
public Test(int test) {
this.test = test;
}
}
}
DEMO
I thought that 5 should have been printed twice. The reason for that is by clonning arrays we're creating new arrays containing references to the objects the first array holded (Because the type of the elemnts does not implement Cloneable). Couldn't you straighten the things out?
It's not clear if it's neccesary the array element's type implements Cloneable.
It's a simple concept, but seems hard to explain. When you clone the array, you will have two district arrays in memory, but with the same values in their indexes.
In your second array an_arr doing an_array[0] = new Test(5) you will put another reference in the slot 0.
But the index 0 of the clone is in a different place from the cloned array.
Your example is valid if you do
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = arr_t.clone();
an_arr[0].test = 5; // look here, I changed the object
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //5
Now both will print the same value because they hold the same reference to the same object, but the place where this reference is stored, is different.
.clone() makes what's called a "shallow copy". That means it copies as little as possible when running the method; instead of copying the contents of the array, it just creates references to the contents of the original array.
If you change the references by calling:
new Test(5)
Then you've overwritten that reference, and get new data.
The alternative is a deep copy of the array. Those can be expensive to do on bigger objects, so they're not the default.
An array's clone() does the same thing regardless of type of array: it creates a new array of the same type and size and then it assigns (=) each element of array to each element of the new array. That's it.
So if you have a 3-element array pointed to by arr, and arr.clone() returns newArr, then after the creation of the new array it simply does this:
newArr[0] = arr[0];
newArr[1] = arr[1];
newArr[2] = arr[2];
That's it. The type of array is not relevant. There is no "cloning" or anything involved in the elements. It doesn't know (or care) if the element has some kind of method to clone (in fact, there is no general API for cloning in Java, anyway, so this would be impossible).
(And by the way, even if it somehow put cloned objects into the new array, the result in your example would still be the same, because you are assigning a new value into the array, so it doesn't matter what was there before.)
So your question is basically why:
Test[] arr_t = new Test[1];
arr_t[0] = new Test(10);
Test[] an_arr = new Test[1];
an_arr[0] = arr_t[0];
an_arr[0] = new Test(5);
System.out.println(an_arr[0].test); //5
System.out.println(arr_t[0].test); //10
and you can figure it out from there.
The "problem" here is that arrays hold references to object, not objects. Further, this has nothing to do with cloning.
When you execute:
an_arr[0] = new Test(5);
You are assigning the new object's reference to the first element.
Also, each array has its own references to Test objects. When you clone the array, only the references are copied (not the objects to which they refer).

Generating dynamic object names within an arrayList in java

I'm doing the last challenge on this forum post called 'graduation' except in Java instead: http://www.cplusplus.com/forum/articles/12974/
I've basically stumbled across a problem where if I have an arrayList of bunny objects that spawns new offspring based on the amount of males and females, I need to give each new offspring a dynamic name for the list or the compiler goes mental and throws a ConcurrentModifierException (which I'm assuming is because it's trying to go through multiple objects that have the same variable name).
The only way I can think of is by making a Bunny object array like saying:
bunnyList.add(bunny[i + 1])
Where i is the kind of 'global' id for all the bunnies. But the problem is that if I add it to the list it's illegal. To be honest, I'm not sure why either since I set the array list to be of type bunny array rather than just plain old bunny.
public class Bunnies {
private static ArrayList<Bunny[]> bunnyList = new ArrayList<Bunny[]>();
private static Bunny[] bunny = new Bunny[500]; //gives it a kind of id
private static int i = 0; //global bunny counter
Bunnies(){
//init the game list.
initBunnyGameList();
}
private void initBunnyGameList(){
for (int i = 0; i < 5; i++){
bunny[i] = new Bunny();
bunnyList.add(bunny[i]); //ILLEGAL :(!
}
}
}
Also doing it this way seems like a massive waste of memory to create an array space for 500 possible bunny objects only to ever use ONE space as an identifier. But I can't seem to think of a way to name each variable dynamically in any other way. Really, what I need is a way to generate variables with a number on the end when I make a bunny so they're all individual no matter what.
Any suggestions hombres?
bunny[i] is actually a Bunny object, not an array of Bunny objects.
private static ArrayList<Bunny[]> bunnyList = new ArrayList<Bunny[]>();
should be
private static ArrayList<Bunny> bunnyList = new ArrayList<Bunny>();

I need to make a copy of an array of cards, but I am only given the address of the array I need to copy

I need to make a temporary copy of an array of cards that I do not have direct access to because it is in another class named Hand. I am given a method called getHand() which returns the reference to the array I need a copy of in the class RummyHand which is a subclass of Hand. The variable rummyHand is an instance variable in the RummyHand class and is a Hand object. Also I am working in eclipse if that matters.
but neither this:
Card[] temp = new Card[8];
temp = rummyHand.getHand();
or this:
Card[] temp = rummyHand.getHand();
has copied the array like I thought it would.
You can use Arrays.copyOf or System.arrayCopy to copy an array, or, more simply, clone():
Card[] temp = rummyHand.getHand().clone();
Note that using the = operator never copies any data. All = does is make a variable refer to a different thing. This is important to understand because otherwise it will cause you a lot of trouble down the road.
In (hopefully useful) detail:
new Card[8];
creates an array: a new area of memory big enough to hold pointers to 8 cards.
Card[] temp
creates a variable that must point to some kind of array of cards. The
=
in the middle makes the variable point to that area of memory. The expression
rummyHand.getHand();
supplies you with the address of a different area of memory. So the line
temp = rummyHand.getHand();
just makes the temp variable point to that area of memory instead. copyOf, arrayCopy and clone all work by creating a new array and filling it with the references from the original array, then handing you back the new array.
use
Card[] hand = rummyHand.getHand();
Card[] temp = new Card[hand.length()];
System.arraycopy(hand,0,temp,0,hand.length());
Afterwards you have a copy of the array - but keep in mind that the references to the cards in the array are still the same. Therefore if you change a property of a card in temp it will also change the card in hand as both arrays contain the same "card instances".
You can use clone to copy an array:
Card[] temp = rummyHand.getHand().clone();
This will give you an exact copy of the same length as the original. If you want the copy eight elements long regardless of the length of the original, you can use Arrays.copyOf:
Card[] temp = Arrays.copyOf(rummyHand.getHand(), 8);
There are a few ways to copy an array. The most basic is to create an array of the same size as the source array, then loop over the elements of the source array and add each one to your new copy:
Card[] source = rummyHand.getHand();
Card[] temp = new Card[source.length];
// for loop:
for (int i = 0; i < source.length; i++)
temp[i] = source[i];
But there are java utility classes that will do this for you. See Arrays.copyOf:
Card[] temp = Arrays.copyOf(source, source.length);
But note that your new array will contain the same Card references as the source array, meaning that any changes to the objects in the array won't change copies: they'll change the actual object. If you need copies of the contents of the array, then you'll need to use the loop, and make a copy of each Card before adding it to the temp array.
When you're doing: temp = rummyHand.getHand();, you're getting a reference to the original array, not a copy, and so any changes that you make will change the array in the rummyHand object..

ArrayList<String> Object assignment

I have two separate objects ArrayList<String> in two separate packages Top and top10. I assign the value of top10 to Top in my activity. And now if I remove an element from Top it also gets removed from top10. I don't know why is this happening? I feel totally dumbfounded. Is there something I don't know about java? Or is it android?
This is my activity code:
ArrayList<String> Top = new ArrayList<String>();
// ServiceCall is the name of the class where top10 is initialized.
Top = ServiceCall.top10;
System.out.println("top WR: "+ServiceCall.top10);
if(Top.get(0).equals("Please Select")) Top.remove(0);
System.out.println("top WR: "+ServiceCall.top10);
The second printed out statement has one element less than the one before.
You are pointing to the same Object.
Top = ServiceCall.top10;
is not creating a new Object, but making a reference to the other one, hence all changes in both pointers will be reflected in the same Object.
You'll have to create a new one passing the other one as parameter:
List<String> Top = new ArrayList<String>(ServiceCall.top10);
You are pointing Top to top10, not creating a new list (your initializer is effectively unused right now, as you are just repointing it to the other list.)
You should do:
ArrayList<String> Top = new ArrayList<String>(ServiceCall.top10);
This will create a shallow copy.

Make a copy of a variable and add to Arraylist

I'm working with two-dimensional array-values that should be inserted into a ArrayList. But this is done in a for-loop and the value of the two-dimensional array-value gets changed as the loop runs since it is just used as an temp-variable (which makes all of the variables stored in the ArrayList gets changed as this variable changes).
So if I try to print out the content of the ArrayList when the loop is done all the values are the same.
for(int i = 0; i <= Counter; i++)
{
if(Xhavetomove >= i)
arrayvalue[0][0] = this.Xspeed;
else
arrayvalue[0][0] = 0;
if(Yhavetomove >= i)
arrayvalue[0][1] = this.Xspeed;
else
arrayvalue[0][1] = 1;
System.out.println(arrayvalue[0][1]);
Object.movement.add(arrayvalue);
}
Are there anyway I can make it store the value itself?
For example: The first time the loop runs the value is "5,5" but if I print out the ArrayList when the loop is done all the values has turned into "5,1".
The problem is the way Array is added to the Object here. You are not adding the Array to the Object. What is happening is you are adding the address to the location in memory where the Array resides. So every time you add the Array to the Object, you are adding the same address every time. So every Array in the Object is actually the same Array over and over since they all point to a single location in memory. So when you change the Array, it will appear to change all of them inside the Object.
The best thing to do is either create a new Array every time through the loop, essentially creating a new location in memory for the Array to reside, or clone() the Array which will create a new reference.
Example:
String[] houseOfStark = {"Eddard", "Catelyn",
"Robb", "Sansa", "Arya", "Bran", "Rickon"}; // Sorry Jon
String[] copyOfStark = houseOfStark;
String[] cloneOfStark = houseOfStark.clone();
houseOfStark[1] = "Lady Catelyn";
System.out.println(houseOfStark[1]);
System.out.println(copyOfStark[1]);
System.out.println(cloneOfStark[1]);
Will produce:
Lady Catelyn
Lady Catelyn
Catelyn
Good blog post explaining the difference
At the end each add needs to create an own object.
To use clone is one way.
Or to add always the values in pairs, in an other.
A totally different way is to use serialization. This make sense when you do not want to calculate this values but to log it. In this case you need an outputStream
What is best is defined by what you want to do with Object.movement
You need to use array's clone() method to make its copy:
//for example
int[][] copy = (int[][])arraySource.clone();

Categories