Java 处理ArrayList和按引用传递
我正在使用arraylist添加状态(8拼图的板状态)。我的问题是,当我获取状态的子级时,它会更改存储在数组列表中的值。我假设这是因为ArrayList只存储指向对象的指针,而不是值本身。为了解决这个问题,我每次在将新对象存储到ArrayList之前都会创建一个新对象,但我仍然遇到同样的问题 我还将尝试更频繁地遵循命名约定,谢谢你的提示Java 处理ArrayList和按引用传递,java,arraylist,Java,Arraylist,我正在使用arraylist添加状态(8拼图的板状态)。我的问题是,当我获取状态的子级时,它会更改存储在数组列表中的值。我假设这是因为ArrayList只存储指向对象的指针,而不是值本身。为了解决这个问题,我每次在将新对象存储到ArrayList之前都会创建一个新对象,但我仍然遇到同样的问题 我还将尝试更频繁地遵循命名约定,谢谢你的提示 private ArrayList<int[][]>VisitedBoard; if(RuleNumber ==2){ /
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;
}
私有ArrayListVisitedBoard;
如果(规则编号==2){
//这是我的问题。这将改变VistedBoards中存储的内容
NextState=新状态(FireRule.Rule2(WM.get_Board());//火灾规则
对于(int j=0;j可能,新的状态
对象包含指向与以前相同的arrayList的指针。您需要手动将数组复制到一个新的数组(称为“深度克隆”或“深度复制”)。您可能会发现这很有用:我的建议是为它们的2D数组创建自己的容器对象并实现深度复制
例如:
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);
}
}
每次创建一个新的State实例时,都会将相同的数组传递给它(由WM.get_Board()
返回的内容)
然后,在调用VisitedBoards.add()
时,将相同的数组添加到VisitedBoards
创建新状态对象的事实与此无关,因为只有NextState.get\u Board()
的返回值才会添加到列表中
因此,列表VisitedBoards始终包含对完全相同数组的多个引用
正如Raffaele所建议的那样,如果您确保get_Board()
返回数组的副本而不是对原始数组的引用(假设这不会扰乱其他地方存在的逻辑),那么就可以了
我从这个问题中学到的主要东西是遵循命名约定有多么重要
你的非常规资本化让我头晕目眩
遵循这些规则将使其他人更容易理解您的Java代码:
- 类名应大写(即PascalCase)
- 变量名应为小写(即大小写)
- 不要在方法名、类名或变量名中使用下划线(它们应仅用于常量)
- 尽可能使用有意义的名称
像ArrayList这样的容器在所有语言中的工作方式都是一样的:它们被称为数据结构,因为它们组织对象的存储/检索。显然,它们不存储对象本身的字段
试图解释您的问题时,可能您不想在已访问的boards
和WM
(无论它是什么意思…)列表之间共享这些boards。然后只需实现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;
}
public int[]get_Board(int[]src){
int[]dst=new int[src.length][src[0].length];
对于(int i=0;i
除此之外,正如其他人已经告诉您的,您最好采用标准的Java命名约定,使用有意义的名称,并封装x
、y
和int[]
在实际的应用程序类中。因为不遵循命名约定,所以很难遵循代码。类名应该大写,变量名应该小写。下划线在Java中不使用(按惯例)。当您习惯了这些约定时,您会惊讶地发现遵循不遵循这些约定的代码有多么困难。请显示任何类NextState
的代码。我们需要查看方法get_Board()
以真正了解发生了什么。我甚至无法理解你在问什么。请检查你的问题,并明确说明你看到的结果和预期结果。可能的话,发布一个简洁的代码示例,显示你的问题并可以运行