Java - Method正在更改同一对象类型的其他实例

时间:2013-03-31 03:35:11

标签: java

下面的方法evalBoard()接受brd,并将其参数复制到pos。然后迭代一些可能的值,通过调用makeMove()对pos进行更改。这些对pos.makeMove的调用也以某种方式改变了brd中的值。通过我在evalBoard中标记的区域可以清楚地看到它。为什么会这样?

public Move evalBoard(Board brd) {
    // evaluates current board and returns point of best move

    Move best;
    Move tmp = new Move(-1, -1, LOSE, brd.getPlayer());
    if (brd.getPlayer() == PLAYER1) {
        best = new Move(-1, -1, LOSE, PLAYER1);
    } else {
        best = new Move(-1, -1, WIN, PLAYER2);
    }
    // check if board is empty if so return optimal move
    //

    if (brd.isEmpty()) {

        return (new Move(0, 0, 0, PLAYER1));

    }

    // iterate through possible moves
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            if (brd.getSpace(x, y) == ' ') {
                // copy all of brd to pos

                pos=new Board(brd.getBoard(),brd.getPlayer());

                tmp.setX(x);
                tmp.setY(y);
                tmp.setPlayer(brd.getPlayer());
/*
 *   problem can be seen by stepping through the next line.  brd is changed at the same time.
*/
                pos.makeMove(tmp);//Problem is here this call is changing brd as well

                // evaluate for immediate win or loss
                if (brd.getPlayer() == PLAYER1) {
                    if (pos.win()) {// immediate win
                        tmp.setValue(WIN);
                        return tmp;
                    } else { // not a winning move check it's recursive
                                // value
                        pos.setPlayer(PLAYER2);
                        tmp.copyFrom(evalBoard(pos));
                        if (tmp.getValue() >= best.getValue()) {
                            best.copyFrom(tmp);
                        }

                    }
                } else {
                    if (pos.win()) {// immediate loss
                        tmp.setValue(LOSE);
                        return tmp;
                    } else {// not a losing move check it's recursive value
                        pos.setPlayer(PLAYER1);
                        tmp.copyFrom(evalBoard(pos));
                        if (tmp.getValue() <= best.getValue()) {
                            best.copyFrom(tmp);
                        }
                    }
                }

            }
        }
    }
    return best;

}

这是董事会成员:

public class Board {
final boolean PLAYER1=true;
final boolean PLAYER2=false;
public char[][] board = new char[3][3];
public boolean Turn;

public Board(char[][] brd,boolean plr1){
    board=brd;
    Turn=plr1;

}
public char getPlayerChar(){
    if (Turn==PLAYER1){
        return 'X';
    }else{
        return 'O';
    }
        }
public char[][] getBoard(){
    return board;
}
public void setBoard(char[][] brd){
    board=brd;
}
public void displayBoard(){
    for(int y=0;y<3;y++){
        for(int x=0;x<3;x++){
            System.out.print(board[x][y]);
            if (x<2){
                System.out.print(" | ");
            } 

        }
        System.out.println("");
        if (y<2){
            System.out.println("----------");

        }

    }
}
public void makeMove(Move mv){
    //System.out.println("hit");

    if (mv.getPlayer()==PLAYER1){
        board[mv.getX()][mv.getY()]='X';
    }else{
        board[mv.getX()][mv.getY()]='O';
    }

}
public void setPlayer(boolean plr){
    Turn=plr;
}
public boolean getPlayer(){
    return Turn;
}
public char getSpace(int x,int y){
    return board[x][y];

}
public boolean isEmpty(){
    for(int x=0;x<3;x++){
        for(int y=0;y<3;y++){

            if(!(board[x][y]==' ')){
                return false;
            }
        }
    }
    return true;
}
public boolean win(){
    char plrChar;
    //returns true if board is winning position for current player
    if (Turn==PLAYER1){
        plrChar='X';
    }else {
        plrChar='O';
    }
    //Across
    for(int y=0;y<3;y++){
        if (board[0][y]+board[1][y]+board[2][y]==(plrChar+plrChar+plrChar)){
            return true;
        }
    }
    //Up/Down
    for(int x=0;x<3;x++){
        if (board[x][0]+board[x][1]+board[x][2]==(plrChar+plrChar+plrChar)){
            return true;
        }
    }
    //Diagonals
        //top left to bottom right
    if (board[0][0]+board[1][1]+board[2][2]==(plrChar+plrChar+plrChar)){
        return true;
    }
        //bottom left to top right
    if (board[0][2]+board[1][1]+board[2][0]==(plrChar+plrChar+plrChar)){
        return true;
    }
    return false;
}


}

1 个答案:

答案 0 :(得分:2)

问题是当你这样做时:

  pos=new Board(brd.getBoard(),brd.getPlayer());

您正在使用原始posboard)创建一个新的董事会(Board分享brd数组。这就是Board构造函数在这里所做的事情:

  public Board(char[][] brd,boolean plr1){
      board=brd;
      ...

当然,由于只有一个数组,当您通过一个Board进行更新时,更改会通过另一个Board显示。

如果您不希望旧的和新的Board实例共享相同的char数组,那么您不应该这样分配。相反,您应该使用嵌套循环将状态从brd复制到board


要学习的课程

这是“漏洞抽象”的一个例子。 getBoardsetBoard方法允许Board外部的代码以相当意外的方式破坏Board实例的状态。这些方法的非泄漏版本和Board构造函数将复制数组的内容(可能是一个新数组),而不是允许Board数组实例在抽象边界之外可访问