2013-03-22 54 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[][]封裝在實際的應用程序類中。