在for循环中用二维char数组创建对象输出不符,疑内存引用问题求助
问题:ArrayList中Student对象的二维数组引用冲突
我尝试创建一个Student对象的ArrayList,但输出结果不符合预期。
Student类代码
class Student{ char[][] charArray; Student(char[][] charArray){ this.charArray = charArray; } void display(){ for (int i = 0; i<4; i++){ System.out.println(this.charArray[i/2][i%2]); } } }
主类代码
public class Testy { public static void main(String[] args) { ArrayList<Student> classrom = new ArrayList<>(); char[][] board = {{'X','-'},{'-','O'}}; for (int i = 0; i<4; i++){ char[][] temp = board.clone(); if(temp[i/2][i%2]!='X'&&temp[i/2][i%2]!='O'){ temp[i/2][i%2] ='X'; classrom.add(new Student(temp.clone())); } } for(Student i: classrom){ System.out.println(i); i.display(); } } }
实际输出
test.Student@2d98a335 X X X O test.Student@16b98e56 X X X O
预期输出
test.Student@2d98a335 X X '-' O test.Student@16b98e56 X '-' X O
我怀疑是多个对象参数指向内存中同一位置导致的,但不知道该如何解决。
解决方案:对二维数组进行深拷贝
你的怀疑完全正确,问题出在二维数组的浅拷贝上。Java里char[][]本质是数组的数组,调用clone()方法只会拷贝外层数组的引用,内层的char[]数组还是指向原内存地址。也就是说,temp = board.clone()执行后,temp[0]和board[0]是同一个数组,修改temp[i/2][i%2]会直接改动原board的内容,后续循环再拷贝时拿到的已经是修改后的数组了。
要解决这个问题,必须对二维数组做深拷贝,也就是逐个拷贝内层的数组,下面提供两种实现方式:
方式1:在主类中手动实现深拷贝
修改主类里的数组拷贝逻辑,替换clone()为手动拷贝内层数组:
public class Testy { public static void main(String[] args) { ArrayList<Student> classrom = new ArrayList<>(); char[][] board = {{'X','-'},{'-','O'}}; for (int i = 0; i<4; i++){ // 深拷贝二维数组:先创建外层数组,再逐个拷贝内层数组 char[][] temp = new char[board.length][]; for (int j = 0; j < board.length; j++) { temp[j] = board[j].clone(); } if(temp[i/2][i%2]!='X'&&temp[i/2][i%2]!='O'){ temp[i/2][i%2] ='X'; // temp已经是独立的数组,直接传入即可 classrom.add(new Student(temp)); } } for(Student i: classrom){ System.out.println(i); i.display(); } } }
方式2:在Student构造方法中处理深拷贝
把深拷贝逻辑放到Student的构造方法里,确保任何传入的数组都会被拷贝为独立副本,避免外部修改影响对象内部:
class Student{ char[][] charArray; Student(char[][] charArray){ // 构造方法内完成深拷贝 this.charArray = new char[charArray.length][]; for (int i = 0; i < charArray.length; i++) { this.charArray[i] = charArray[i].clone(); } } void display(){ for (int i = 0; i<4; i++){ System.out.println(this.charArray[i/2][i%2]); } } }
这种情况下,主类里的temp.clone()可以换成上述的深拷贝逻辑,或者直接传入temp,因为构造方法会自动处理数组的独立拷贝。
原代码问题解析
board.clone()仅拷贝外层数组引用,内层char[]与原数组共享内存- 第一次循环修改
temp[0][1]为'X',直接修改了原board[0][1]的值 - 第二次循环拷贝
board时,board[0][1]已经是'X',修改temp[1][0]为'X'又改动了原board[1][0] - 最终两个Student对象的
charArray都指向了最后修改后的board数组,所以输出完全相同
修改后,每次循环都会创建完全独立的二维数组,每个Student对象持有自己的数组副本,输出就能符合预期。
内容的提问来源于stack exchange,提问作者maksymilian wojciechowski
相关产品推荐
相关产品推荐

