user2015858
user2015858

Reputation: 47

Dealing with ArrayList and pass by reference

I'm using a arraylist to add states(the board state for the 8 puzzle). My problem is when I get the children of the state it changes the values stored in my array list. I'm assuming this is because ArrayList just stores pointers to the objects and not the values themselves. In order to fix this I create a new object every time before I store it into the ArrayList but I'm still having the same problem.

I will also try to follow naming conventions more often thanks for the tip.

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

}

Upvotes: 0

Views: 164

Answers (4)

George
George

Reputation: 13

My advice is to create your own container object for their 2D array and implement deep copying.

For example:

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

Upvotes: 0

Raffaele
Raffaele

Reputation: 20875

Containers like ArrayList work the same in all languages: they are called data structures because they organize storage/retrieval of objects. Obviously they don't store the fields of the objects themselves.

Trying to interpret your problem, maybe you don't want to share the boards between the list of visitedBoards and WM (whatever it means...). Then simply implement get_Board() to return a copy of the array instead of the Board object itself:

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

Beside this, as others already told you, you'd really better to adopt the standard Java naming conventions, use meaningful names, and encapsulate your x, y and int[][] in real application classes.

Upvotes: 1

jahroy
jahroy

Reputation: 22692

Every time you create a new instance of State, you pass it the same array (whatever is returned by WM.get_Board()).

You then add that same array to VisitedBoards when you call VisitedBoards.add().

The fact that you're creating new State objects is irrelevant, because only the return value of NextState.get_Board() gets added to the list.

As a result, the list VisitedBoards always contains several references to the exact same array.

As Raffaele has suggested, you'll be fine if you make sure get_Board() returns a copy of the array in stead of a reference to the original (assuming that doesn't mess up logic that exists elsewhere).


The main thing I learned from this question is how important it is to follow naming conventions.

Your unconventional capitalization has made me dizzy!

Following these rules will make it much easier for others to understand your Java code:

  • class names should be capitalized (ie PascalCase)
  • variable names should be lowercase (ie camelCase)
  • do not use underscores in method names, class names, or variable names (they should only be used for constants)
  • always use meaningful names when possible

Upvotes: 0

Nick
Nick

Reputation: 2845

Presumably, the new State object contains a pointer to the same arrayList as before. You'll want to manually copy the array out to a new one (a "deep clone" or "deep copy" as it is called). You might find this useful: Deep cloning multidimensional arrays in Java...?

Upvotes: 0

Related Questions