Java调用ArrayList.add()仅更新首元素未追加新元素问题
问题现象
- 编写国际象棋黑象(BlackBishop)类的合法移动坐标计算逻辑时,调用
ArrayList.add()方法无法将元素追加到列表末尾,列表索引为0的首元素会随循环执行持续更新 - 查阅ArrayList官方文档后尝试改用
add(index, element)重载方法,问题仍然存在 - 测试用例为实例化
new BlackBishop(7,3),传入参数分别对应国际象棋棋盘第7行、第3列(C列)
原实现代码
import java.util.ArrayList; public class BlackBishop extends Item{ BlackBishop(int y, int x){ name='F'; point=3; this.y=y; this.x=x; availableMoves(); } public ArrayList<Integer[]> availableMoves(){ int finalY=0; int finalX=0; Integer[] move=new Integer[2]; ArrayList<Integer[]> avMoves=new ArrayList<>(); for(int i=1;i<8;i++){ if(x-i>0&&y-i>0){ finalY=y-i; finalX=x-i; move[0]=finalY; move[1]=finalX; avMoves.add(move); } System.out.println(avMoves.get(0)[0]+" "+avMoves.get(0)[1]); if(x-i>0&&y+i<=8){ finalY=y+i; finalX=x-i; move[0]=finalY; move[1]=finalX; avMoves.add(move); } System.out.println(avMoves.get(0)[0]+" "+avMoves.get(0)[1]); if(x+i<=8&&y-i>0){ finalY=y-i; finalX=x+i; move[0]=finalY; move[1]=finalX; avMoves.add(move); } if(x+i<=8&&y+i<=8){ finalY=y+i; finalX=x+i; move[0]=finalY; move[1]=finalX; avMoves.add(move); } } return avMoves; } }
运行输出
6 2 8 2 5 1 5 1 5 5 5 5 4 6 4 6 3 7 3 7 2 8 2 8 2 8 2 8
从输出可以看到,列表首元素的值随循环持续变化,没有按预期存储所有计算得到的合法移动坐标。
根本原因
问题和ArrayList的add方法实现无关,出在数组对象的引用逻辑上:
- 代码在for循环外部只创建了一次
Integer[] move = new Integer[2];数组对象 - Java中数组是引用类型,调用
avMoves.add(move)时,存入列表的不是当前move数组的内容拷贝,而是这个数组对象的内存引用 - 循环过程中反复修改
move[0]、move[1]的值时,所有列表条目因为都指向同一个数组对象,读取到的值都会同步更新 - 最终整个ArrayList里存储的全是同一个数组的引用,值为循环最后一次给move数组赋值的坐标,因此每次读取索引0的元素,都会看到值被最新的计算结果覆盖。
修复方法
每次往列表添加移动坐标前,新建一个独立的Integer[]数组对象,不要复用循环外创建的同一个数组实例,保证每个列表条目指向独立的数组对象,修改操作不会互相影响。
修复后的核心逻辑代码:
public ArrayList<Integer[]> availableMoves(){ int finalY=0; int finalX=0; ArrayList<Integer[]> avMoves=new ArrayList<>(); for(int i=1;i<8;i++){ if(x-i>0&&y-i>0){ finalY=y-i; finalX=x-i; // 每次添加前创建新的数组实例 Integer[] move=new Integer[2]; move[0]=finalY; move[1]=finalX; avMoves.add(move); } System.out.println(avMoves.get(0)[0]+" "+avMoves.get(0)[1]); if(x-i>0&&y+i<=8){ finalY=y+i; finalX=x-i; Integer[] move=new Integer[2]; move[0]=finalY; move[1]=finalX; avMoves.add(move); } System.out.println(avMoves.get(0)[0]+" "+avMoves.get(0)[1]); if(x+i<=8&&y-i>0){ finalY=y-i; finalX=x+i; Integer[] move=new Integer[2]; move[0]=finalY; move[1]=finalX; avMoves.add(move); } if(x+i<=8&&y+i<=8){ finalY=y+i; finalX=x+i; Integer[] move=new Integer[2]; move[0]=finalY; move[1]=finalX; avMoves.add(move); } } return avMoves; }
内容的提问来源于stack exchange,提问作者Emin K.L.
相关产品推荐
相关产品推荐

