I need to clone a 2d array of Cell objects but it doesn't work as it should. Whenever i clone the maze, it clones it but when i make changes to one, it is also visible on the other
somebody knows what the problem is???
public void cloneMaze(boolean backup)
{
if (backup) {
backupMaze = (Cell[][]) maze.clone();
for (int i = 0; i < maze.length; i++) {
backupMaze[i] = (Cell[]) maze[i].clone();
}
} else {
maze = (Cell[][]) backupMaze.clone();
for (int i = 0; i < backupMaze.length; i++) {
maze[i] = (Cell[]) backupMaze[i].clone();
}
}
}
In your backup maze, you need to create new Cell that are a copy of the first ones
Otherwise both your mazes point to the same objects, thus modification to the cells are reflected in both mazes.
clone() is just a shallow copy of your array, while you seem to look for deep copy.
Related
I'm trying to create a calendar using Java GUI and I want to create a method to create the cells of each date. Is there any way to create a method to create a bunch of JTextAreas without manually creating each individual cell?
Creating a cell one by one I do:
public void createCell() {
cell1 = new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS);
}
You have many ways of doing that one possibility would be to create a List inside the method with the assistance of a for loop and make the method return it for you to use somewhere else.
public List<JTextArea> createMultipleCells(int numOfCells) {
List<JTextArea> cells = new LinkedList<JTextArea>();
for(int i = 0; i < numOfCells; i++){
cells.add(new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS));
}
return cells;
}
Same thing with an array:
public JTextArea[] createMultipleCells(int numOfCells) {
JTextArea[] cells = new JTextArea[numOfCells];
for(int i = 0; i < numOfCells; i++){
cells[i] = new JTextArea(CELL_DIMENSIONS, CELL_DIMENSIONS);
}
return cells;
}
I'm building a Java based game in Swing, which is essentially a grid of Jbuttons
I have an Object called Cell, which is a custom JButton with additional parameters for storing objects. The game grid is represented by Cell[][]
I have an arraylist of type Cell[][] to allow me to store the state of the gamegrid after each move. If I want to undo the move, I need to copy the last element of the ArrayList to the game grid to allow it to be displayed on the UI.
My gamegrid is panelHolder and my arraylist is moveHolder.
So far I've tried Collections.copy(panelHolder, moveHolder.get(moveHolder.size())); which will not compile due to the "arguments not being applicable for the type Cell[][]"
I've also tried System.arraycopy(moveHolder.get(moveHolder.size()-1), 0, panelHolder, 0, panelHolder.length);, which throws and out of bounds exception. Initially I thought this was due to the moveHolder.size()-1, but even just as moveHolder.size() it has the same problem.
I've found numerous questions on StackOverflow and others that both show these two ways of doing it, but I can't seem to get it to work. Is there something more obvious I'm missing? Full class method below:
public class UndoClass implements MoveCommand{
public ArrayList<Cell[][]> moveHolder = new ArrayList<Cell[][]>();
public Cell[][] execute(Cell[][] panelHolder) {
if (moveHolder.size() > 0){
Collections.copy(panelHolder, moveHolder.get(moveHolder.size()));
if (moveHolder.size() > 0){
moveHolder.remove(moveHolder.size());
}
}
System.out.println("Move Undone. Undos available:" + moveHolder.size());
return panelHolder;
}
public void addMove(Cell[][] panelHolder){
moveHolder.add(panelHolder);
}
public ArrayList<Cell[][]> getMoves(){
return moveHolder;
}
}
Cell Class
public class Cell extends JButton {
int co_x = 0;
int co_y = 0;
ArrayList<Players> current = new ArrayList <Players>();
}
Just wanted to point our your execute(...) method accepts the Cell[][] both as a parameter and the return argument. That approach is going to force all of your commands to keep copying your input param arrays to the return statement array. Notice if you don't need to keep the two in sync and you just use the return arg, you don't have to worry about copying at all:
Cell[][] lastState = moveHolder.get(moveHolder.size()-1);
moveHolder.remove(moveHolder.size()-1);
return lastState; // Not updating the panelHolder array, just returning
But of course now the input parm and return are out of sync. Instead you might want to encapsulate that state into a single object to make your life easier. Something like this (note that the execute now returns a void):
public ArrayList<GameState> previousStates = new ArrayList<GameState>();
public void execute(GameState currentState) {
if (previousStates .size() > 0) {
GameState lastState = previousStates.get(previousStates.size()-1);
currentState.restoreFrom(lastState);
previousStates .remove(moveHolder.size()-1);
}
}
Good luck on the game!
if (moveHolder.size() > 0) {
for (int i = 0; i < panelHolder.length; i++) {
panelHolder[i] = moveHolder.get(moveHolder.size()-1)[i].clone();
}
moveHolder.remove(moveHolder.size()-1);
}
Try this. You need to make copies of each internal array when copying 2D arrays.
Try a Linked List
LinkedList<Cell[][]> ll = new LinkedList();
ll.removeLast();
panelHolder = ll.clone();
Is there anything wrong in these two methods that copy & returns an array?
This is how i called it :
o2[i].addArr(o1.getArr());
And at the end the result is that o2[i].getArr(); is empty. I don't know why but this is my code if you could help me
NOTE: The class Array i wrote it here Array while it's another class name in my code. just to make it clear for you
public Array[] getArr(){ //first method
int count=0;
for(int i=0;i<10;i++){
if(Arrlist[i]!=null)
count++;}
Array[] arr=new Array[count];
for(int i=0;i<count;i++)
arr[i]=Arrlist[i];
return arr;}
public void addArr(Array[]arr){ //second method
for(int i=0;i<arr.length;i++)
Arrlist[i]=arr[i];
}
Yes. In getArr, you're going to overrun the length of the array you're creating if you have any null entries in the array you're copying.
In the loop where you're actually copying, you need separate variables for the index into arr and the index into Arrlist, because you need to skip nulls.
E.g., along these lines (untested):
int i, j;
j = 0;
for (i = 0; i < Arrlist.length; ++i) {
if (Arrlist[i] != null) {
arr[j++] = Arrlist[i];
}
}
addArr is okay if (and it's a big "if") Arrlist is allocated and it's the same size as arr. (You could replace it with System.arraycopy.) Note that the name is misleading, though; you're overwriting Arrlist, not adding to it. And again, those are some pretty big "if"s.
I am trying to submit this sound manipulation program, but I keep getting this error:
Assignment requires a deep, not shallow copy. Are you just copying pointers, or copying the contents of the array?...
I think I am doing a shallow copy on my public void set(double[] mySamples), but I am new to Java and really don't know what to do.
public class Sound
{
private double[] temp;
private double[] samples;
public Sound() {
samples = null;
}
public Sound(Sound s) {
int j = 0;
double[] source = s.samples;
double temp[] = new double[source.length];
for(int i = 0; i < source.length; i++) {
temp[j] = source[i];
}
samples = temp;
}
public double[] get() {
return samples;
}
public void set(double[] mySamples) {
if (mySamples == null) {
throw new IllegalArgumentException("samples cannot be null");
} else {
samples = mySamples;
}
}
public void increaseVol(double percent) {
double [] result = new double[samples.length];
for (int i = 0; i < samples.length; i++) {
double reduce = samples[i] * percent;
result[i] = samples[i] + reduce;
}
samples = result;
}
public void wavSave(java.lang.String fileName) {
WavIO.write(fileName, samples);
}
}
I think you need to make two changes -
1 Your constructor is doing something weird with those samples (and might be causing your error by itself) - I'm not sure what you were trying to do, but I think you should just defer to set.
public Sound(Sound s) {
int j = 0;
set(s.samples);
}
2 Just copy the samples array in set, and store it.
public void set(double[] mySamples) {
if (mySamples == null) {
throw new IllegalArgumentException(
"samples cannot be null");
} else {
samples = new double[mySamples.length];
for (int i = 0; i < mySamples.length; i++) {
samples[i] = mySamples[i];
}
}
}
Yes, you're doing "shallow" copies. Arrays in Java are like pointers, in that if you return or set an array, it's just a pointer (really, reference) to that array. With your current code it's pretty easy for different Sound objects to reference the same underlying array, which is probably not what you want.
In the set method, you need to copy the contents of the array instead of just copying the reference to that array.
You do copy the contents of the array properly in the Sound(Sound s) constructor. However, you don't need to manually allocate a new array and write a for-loop to copy the values. Just call java.util.Arrays.copyOf() to copy it. You can use a similar technique in the set method.
The get method also has the issue where it's returning a reference to the array from inside your Sound object. The caller now has a reference to the Sound object's internal state and can manipulate it. That might or might not be what you want.
Primitive arrays and arrays of autoboxed reference types (from primitives) are final and immutable. Therefore, they are ideal candidates for the clone() method.
You can edit this code:
public void set(double[] mySamples) {
if (mySamples == null) {
throw new IllegalArgumentException(
"samples cannot be null");
} else {
samples = new double[mySamples.length];
for (int i = 0; i < mySamples.length; i++) {
samples[i] = mySamples[i];
}
}
}
into this with the same functionality and superior performance:
public void set(double[] mySamples) {
if (mySamples == null || mySamples.length < 1) {
throw new IllegalArgumentException(
"samples cannot be null or empty");
}
samples = mySamples.clone();
}
This works safely because doubles are immutable and primitive and so a shallow copy is the same as a deep copy in this case. It's also safe because double cannot be subclassed and so no mischief is possible with clone().
Moreover, the performance of clone() on arrays is much, much faster than iterating over an array in code and copying element by element.
TL;DR: Making a copy of an array of primitives (or an array of the corresponding autoboxed reference types that correspond to a primitive) is quite possibly the only case in which it is ideal to use the clone() method.
So lets say I want to make a deep copy of an object, but using its contsructor. So I have:
public class PositionList {
private Position[] data = new Position[0];
private int size = 0;
public PositionList(PositionList other, boolean deepCopy) {
if (deepCopy==true){
size=other.getSize();
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
}
else {
data=other.data;
size = other.size;
And so say I have this being called:
PositionList list = new PositionList();
PositionList acopy = new PositionList(list, true);
What I am doing, however, is incorrect, and Im not sure why..
The problem lies in your deep copy logic:
size=other.getSize();
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
You are setting the size field (which is redundant with the data array) but are not assigning a new array to the data field, which is presumably the whole point of your "deep" copy. You should initialize data to the other's size (or other.data.length):
data = new Position[other.data.length];
for (int i=0;i<data.length;i++)
data[i]=other.data[i];
(And get rid of size all together)