2013-03-22 55 views
0

我使用arraylist添加状态(8拼图板状态)。我的问题是当我得到状态的孩子时,它改变了存储在我的数组列表中的值。我假设这是因为ArrayList只存储指向对象的指针而不是值本身。为了解决这个问题,我在每次将它存储到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; 
} 

}

+0

由于您不遵循命名约定,因此很难遵循您的代码。类名应该大写,变量名应该是小写。 Java中不使用下划线(通常)。当你习惯使用不遵循这些约定的代码时,你会感到惊讶。 – jahroy 2013-03-22 22:01:46

+0

请显示“NextState”类的代码。我们需要看看'get_Board()'方法真的知道发生了什么。 – jahroy 2013-03-22 22:03:24

+0

我甚至都不明白你在问什么。请检查你的问题,并明确指出你看到的结果和预期的结果。可能,发布一个简明的代码示例,显示您的问题,并可以运行 – Raffaele 2013-03-22 22:13:43

回答

0

据推测,新State对象包含一个指向相同的ArrayList如前。您需要手动将数组复制到新数组中(称为“深克隆”或“深度复制”)。你可能会觉得这很有用:Deep cloning multidimensional arrays in Java...?

+0

问题解决非常感谢你尼克! – user2015858 2013-03-22 22:48:33

+0

不客气! – Nick 2013-03-22 22:51:01

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

创建国家的新实例每次,你传递相同的数组(无论是通过WM.get_Board()返回)。

然后,当您拨打VisitedBoards.add()时,您将同样的数组添加到VisitedBoards

事实上,您正在创建新的状态对象是不相关的,因为只有返回值NextState.get_Board()被添加到列表中。

因此,名单VisitedBoards总是包含几个引用到完全相同的数组。

正如Raffaele所说的,如果您确定get_Board()返回数组的副本而不是对原始数据的引用(假设不会混淆其他地方存在的逻辑),那么您会好起来的。


我从这个问题中学到的主要东西是遵循命名约定的重要性。

你的非常规大写让我头晕!

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

  • 类名应该大写(即PascalCase)
  • 变量名应该是小写(即驼峰)
  • 在方法名称,类名称或变量名称中不使用下划线(它们只应用于常量)
  • 在可能的情况下始终使用有意义的名称
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命名约定,使用有意义的名称,并将您的xyint[][]封装在实际的应用程序类中。