0

我正在使用数组列表添加状态(8 谜题的棋盘状态)。我的问题是当我得到状态的孩子时,它会改变存储在我的数组列表中的值。我假设这是因为 ArrayList 只存储指向对象的指针而不是值本身。为了解决这个问题,我每次都在将它存储到 ArrayList 之前创建一个新对象,但我仍然遇到同样的问题。

感谢您的提示,我还将尝试更频繁地遵循命名约定。

 private ArrayList<int[][]>VisitedBoard; 

 if(RuleNumber ==2){
         //Here is my problem. This will change what is stored in VistedBoards
          NextState =  new State(FireRule.Rule2(WM.get_Board()));//Fire Rule

          for(int j=0;j<VisitedBoards.size();j++){
              //Meaning this will always be true
              if(Arrays.equals(VisitedBoards.get(j), NextState.get_Board())){
                  Loop =true; //Loop to previous state
              }
              if(j==VisitedBoards.size()-1 && Loop ==false){ //If the next state is not any previously visited
                  NotALoop =true;
                  VisitedBoards.add(NextState.get_Board());
                  WM.set_Board(NextState.get_Board());

              }
          }
      }




public int[][] Rule2(int [][] Board){//The FireRule Class
    Find_BlankLocation(Board);
    int temp; 
    State NewState;
    temp = Board[BlankLocation[0]-1][BlankLocation[1]];
    Board[BlankLocation[0]-1][BlankLocation[1]] = 0;
    Board[BlankLocation[0]][BlankLocation[1]] = temp;
    NewState = new State(Board);
    return Board;
}





public class State { //State class
private int[][] Board;
private int[][] Goal; 
private Boolean GoalFound;

public State(int[][] Start, int[][] goal){
    Board = Start;
    Goal = goal;
    GoalFound=false;
}
public State(int[][] NewState){
    Board=NewState;
}
public int[][] get_Goal(){
    return Goal;
}
public int[][] get_Board(){
    return Board;
}
public void set_Board(int[][] board){
    Board = board;
}
public Boolean get_GoalFound(){
    return GoalFound;
}

}

4

4 回答 4

1

类似容器ArrayList在所有语言中的工作方式都是一样的:它们被称为数据结构,因为它们组织对象的存储/检索。显然他们不存储对象本身的字段。

试图解释你的问题,也许你不想在和列表之间共享板子visitedBoardsWM不管它是什么意思......)。然后简单地实现get_Board()返回数组的副本而不是Board对象本身:

public int[][] get_Board(int[][] src) {
  int[][] dst = new int[src.length][src[0].length];
  for (int i = 0; i < src.length; i++) {
    System.arraycopy(src[i], 0, dst[i], 0, src[i].length);
  }
  return dst;return dst;
}

除此之外,正如其他人已经告诉您的那样,您最好采用标准的 Java 命名约定,使用有意义的名称,并将您的x,yint[][]实际应用程序类封装起来。

于 2013-03-22T22:26:51.930 回答
0

每次创建 State 的新实例时,都将相同的数组传递给它(无论返回什么WM.get_Board())。

然后,您在调用时将相同的数组添加到VisitedBoardsVisitedBoards.add()

您正在创建新的 State 对象这一事实是无关紧要的,因为只有 的返回值NextState.get_Board()被添加到列表中。

因此,VisitedBoards列表始终包含对完全相同数组的多个引用。

正如 Raffaele 所建议的那样,如果您确保get_Board()返回数组的副本而不是对原始数组的引用(假设这不会弄乱其他地方存在的逻辑),那么您会很好。


我从这个问题中学到的主要内容是遵循命名约定是多么重要。

你那标新立异的大写让我头晕目眩!

遵循这些规则将使其他人容易理解您的 Java 代码:

  • 类名应大写(即 PascalCase)
  • 变量名应为小写(即 camelCase)
  • 不要在方法名、类名或变量名中使用下划线(它们只能用于常量)
  • 尽可能使用有意义的名称
于 2013-03-22T22:25:22.020 回答
0

我的建议是为他们的二维数组创建自己的容器对象并实现深度复制。

例如:

package netbeans;

import java.util.Arrays;

public class Container
implements Cloneable
{
private int [] _data;
private int _sx;
private int _sy;

public int get(int x, int y)
{
    try { return this._data[y*this._sx+x]; }
    catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}

public void set(int x, int y, int value)
{
    try { this._data[y*this._sx+x] = value; }
    catch (Exception e) { throw new ArrayIndexOutOfBoundsException(); }
}

public Object Clone() { return new Container(this); }

public Container(int sizeX, int sizeY, int [] data)
{
    this._sx = sizeX;
    this._sy = sizeY;
    this._data = data;
}

public Container(Container cont)
{
    this._data = Arrays.copyOf(cont._data, cont._data.length);
}
}
于 2013-03-22T22:12:24.903 回答
0

据推测,新State对象包含一个指向与以前相同的arrayList 的指针。您需要手动将阵列复制到一个新阵列(称为“深度克隆”或“深度复制”)。您可能会发现这很有用:Deep cloning multidimensional arrays in Java...?

于 2013-03-22T22:04:04.997 回答