Java ArrayList无法保留Table对象不同状态的问题排查
问题原因分析
你的代码核心问题是对象引用复用,以及状态回滚的逻辑错误:
- 所有列表元素指向同一个Table实例:你执行
moves.add(this)时,并没有创建当前Table状态的副本,而是把当前Table对象的引用添加到列表里。整个moves列表里的所有元素其实都是同一个对象的引用,后续对this的任何修改(包括恢复初始位置)都会影响列表里的所有"元素"。 - 状态回滚逻辑覆盖了已保存的引用:循环中你修改cube位置验证合法后,调用
this.setCubes(currentTable)(currentTable是原状态引用,且你已修改其中的cube对象),然后添加this到列表。但后续循环会把cube位置恢复为backupX和backupY——因为所有列表元素都指向同一个this对象,最终所有元素的状态都会被重置为初始状态。 - 循环内print能显示不同状态是时机问题:循环内的
moves.get(0).printTable()是在修改cube位置还没恢复时执行的,此时this是刚修改后的状态;但循环结束后所有cube都恢复到初始位置,此时访问列表任意索引,都是指向已恢复初始状态的this对象,所以只能打印初始状态。
修复方案
要解决问题,你需要为每个合法移动状态创建Table对象的深拷贝,而非复用同一个对象引用:
实现Table的拷贝构造函数
给Table类添加拷贝构造函数,复制当前Table的所有状态(包括Cube对象的深拷贝,避免共享Cube引用):public Table(Table other) { this.K = other.getK(); // 深拷贝Cube列表 this.cubes = new ArrayList<>(); for (Cube cube : other.getCubes()) { // 假设Cube有拷贝构造函数,复制ID和位置 this.cubes.add(new Cube(cube.getId(), cube.getPosX(), cube.getPosY())); } }修改generateMoves方法逻辑
验证到合法移动时,创建当前状态的Table副本添加到列表,再恢复原cube位置:public ArrayList<Table> generateMoves(){ ArrayList<Table> moves = new ArrayList<Table>(); ArrayList<Cube> currentTable = this.getCubes(); int K = this.getK(); for(Cube cube : currentTable){ int backupX = cube.getPosX(); int backupY = cube.getPosY(); for(int Y = 1; Y <= 3; Y++){ for(int X = 1; X <= 4*K; X++){ // 跳过原位置,避免生成重复状态 if (X == backupX && Y == backupY) { continue; } cube.setPosX(X); cube.setPosY(Y); if(cube.isValid(currentTable) && cube.isFree(currentTable)){ // 创建当前状态的深拷贝并添加到列表 Table newTable = new Table(this); moves.add(newTable); } // 恢复cube原位置 cube.setPosX(backupX); cube.setPosY(backupY); } } } // 此时打印列表元素,每个都是独立状态 for (Table table : moves) { table.printTable(); } return moves; }确保Cube对象的深拷贝
给Cube类也实现拷贝构造函数,避免不同Table实例共享同一个Cube对象,防止修改一个Table的Cube影响其他Table。
内容的提问来源于stack exchange,提问作者Stelios P.98
相关产品推荐
相关产品推荐

