You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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,因为构造方法会自动处理数组的独立拷贝。

原代码问题解析

  1. board.clone()仅拷贝外层数组引用,内层char[]与原数组共享内存
  2. 第一次循环修改temp[0][1]为'X',直接修改了原board[0][1]的值
  3. 第二次循环拷贝board时,board[0][1]已经是'X',修改temp[1][0]为'X'又改动了原board[1][0]
  4. 最终两个Student对象的charArray都指向了最后修改后的board数组,所以输出完全相同

修改后,每次循环都会创建完全独立的二维数组,每个Student对象持有自己的数组副本,输出就能符合预期。


内容的提问来源于stack exchange,提问作者maksymilian wojciechowski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:15:25