1

I am writing a chess game in Java. I have a Board class that contains the String 2D array board. I need to be able to create a tempBoard that copies the mainBoard. Make some changes and run tests on tempBoard without changing the 2d array in mainBoard.

public class Board implements Cloneable {

public String[][] board = new String[][]{
    {"bR ", "bN ", "bB ", "bQ ", "bK ", "bB ", "bN ", "bR "},
    {"bp ", "bp ", "bp ", "bp ", "bp ", "bp ", "bp ", "bp "},
    {"   ", "## ", "   ", "## ", "   ", "## ", "   ", "## "},
    {"## ", "   ", "## ", "   ", "## ", "   ", "## ", "   "},
    {"   ", "## ", "   ", "## ", "   ", "## ", "   ", "## "},
    {"## ", "   ", "## ", "   ", "## ", "   ", "## ", "   "},
    {"wp ", "wp ", "wp ", "wp ", "wp ", "wp ", "wp ", "wp "},
    {"wR ", "wN ", "wB ", "wQ ", "wK ", "wB ", "wN ", "wR "}
};


public Board() {

}

@Override
public Object clone() throws CloneNotSupportedException {
    return super.clone();
}

}

Board tempBoard = (Board ) Mainboard.clone();
                    tempBoard.updateBoard(move);

^ in another class in main I am attempting to updateBoard on tempBoard but this is also changing the array in mainBoard. Any suggestions?

ThatHybrid
  • 383
  • 2
  • 3
  • 9

4 Answers4

2

Java's clone() is troublesome. Try a copy constructor.

public static Board newInstance(Board board)
{
    // Set fields as appropriate to your Board class
    return new Board(board.getFoo(), board.getBar());
}
MarsAtomic
  • 10,436
  • 5
  • 35
  • 56
1

Your cloned object is referencing the same board array. A possible solution would be:

@Override
public Object clone() throws CloneNotSupportedException {
    Board b = new Board();
    b.board = (String[][]) this.board.clone();
    return b;
}
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • clone should call the parent's clone() method and never the constructor, see http://stackoverflow.com/questions/1052340/what-is-wrong-with-this-clone/1053227#1053227 – Steve Kuo Mar 23 '15 at 19:46
  • @SteveKuo `public Object clone() { Board clone = (Board).super.clone(); return clone; }` this is throwing an error under (Board) – ThatHybrid Mar 23 '15 at 20:03
0

The first issue here is that your implementation of cloneable is just calling the parent class's method. The parent class has no idea about your board property so it can't clone that. The reason this doesn't throw an exception is because you still get a reference to the board property when you're casting the return of MainBoard.clone() to Board. You should actually implement the clone method and return a copy of the current instance.

You should also avoid casting objects. There are few situations where casting is necesary and makes sense but most of the times it aids to the confusion regarding an object's type.

Hope I helped.

0

"clone" is a minefield in Java. I recommend not using the Cloneable interface or making a clone method. A search on "Java clone" will probably give you a lot of information on this.

  • I'd recommend a copy() method.
  • Copy usually means make a copy that is separate from the original, which is what you want to do. This gets into mutable and immutable objects. You want an immutable object, which means it can't be changed. Usually, that means that any fields are private and there are no setter methods for the fields. The complication comes when an object is composed of other objects. You can make the top level object immutable, but if the objects within are mutable, and those objects can be accessed elsewhere, then the top object isn't really immutable.

Here's an example:

public class Widget {
    public int number = 0;
    public String name = "";
}

public class BunchOfWidgets {
    private List<Widget> bunch;
    public BunchOfWidgets(List<Widgets> widgetsIn) {
        bunch = widgetsIn;
    }
    public String getName(int i) {
       return bunch.get(i).name;
    }
}

Then somewhere else you make a bunch of widgets:

List<Widgets> listOfMutableWidgets = getMutableWidgetList();
BunchOfWidgets immutableBunch = new BunchOfWidgets(listOfMutableWidgets);
listOfMutableWidgets.get(0).number = 1;
listOfMutableWidgets.get(0).name = "Metamorph";

Now immutableBunch is immutable, but you changed the name field of the first element in that private List. The list is private, but the elements are not.

So you have to be careful that the objects are immutable at all levels. That means the fields must be private, get methods need to return copies of field values, and if constructors have Object arguments that set private fields, the arguments are copied field by field (recursively downward if necessary) to private fields within your class. Copying primitive types is safe since they are not objects, but rather values. String's are immutable, but what String is at a given index in an array or Collection is not, unless you make the array or Collection immutable. The same is true for removing Strings. The same logic applies to any immutable object in a mutable array or Collection.

wdb
  • 333
  • 1
  • 3
  • 13