我需要帮助在Java中复制一个对象

时间:2015-03-23 19:28:34

标签: java oop

我正在用Java编写国际象棋游戏。我有一个包含String 2D阵列板的Board类。我需要能够创建一个复制mainBoard的tempBoard。在不更改mainBoard中的2d数组的情况下,对tempBoard进行一些更改并运行测试。

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);

^在main中的另一个类我试图在tempBoard上更新BOBard,但这也改变了mainBoard中的数组。有什么建议?

4 个答案:

答案 0 :(得分:2)

Java的clone()是troublesome。尝试复制构造函数。

public static Board newInstance(Board board)
{
    // Set fields as appropriate to your Board class
    return new Board(board.getFoo(), board.getBar());
}

答案 1 :(得分:1)

您的克隆对象引用相同的板阵列。可能的解决方案是:

@Override
public Object clone() throws CloneNotSupportedException {
    Board b = new Board();
    b.board = (String[][]) this.board.clone();
    return b;
}

答案 2 :(得分:0)

这里的第一个问题是你cloneable的实现只是调用父类的方法。父类不知道您的board属性,因此它无法克隆它。这不会引发异常的原因是因为当您将MainBoard.clone()的返回值转换为Board时,您仍然会获得对该属性的引用。您应该实际实现clone方法并返回当前实例的副本。

您还应该避免投射对象。在很少的情况下,铸造是必要的并且是有意义的,但大多数时候它有助于混淆对象的类型。

希望我帮助过。

答案 3 :(得分:0)

“clone”是Java中的一个雷区。我建议不要使用Cloneable接口或制作克隆方法。搜索“Java clone”可能会为您提供大量信息。

  • 我建议使用copy()方法。
  • 复制通常意味着制作一份与原版分开的副本,这是您想要做的。这进入了可变和不可变的对象。您需要一个不可变对象,这意味着它无法更改。通常,这意味着任何字段都是私有的,并且字段没有setter方法。当一个对象由其他对象组成时,就会出现这种复杂情况。您可以使顶级对象不可变,但如果其中的对象是可变的,并且这些对象可以在其他地方访问,那么顶级对象实际上不是永久不变的。

以下是一个例子:

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;
    }
}

然后在其他地方制作一堆小部件:

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

现在immutableBunch是不可变的,但是您更改了该私有List中第一个元素的名称字段。 列表是私有的,但元素不是。

所以你必须要小心对象在所有级别都是不可变的。这意味着字段必须是私有的,get方法需要返回字段值的副本,如果构造函数具有设置私有字段的Object参数,则逐字段(必要时递归向下)复制参数你班上的私人领域。复制基元类型是安全的,因为它们不是对象,而是值。字符串是不可变的,但是除非你使数组或集合不可变,否则String在数组或Collection中的给定索引处不是。删除字符串也是如此。相同的逻辑适用于可变数组或集合中的任何不可变对象。