【问题标题】:What is the the difference between these reference copying in the JAVA?这些参考复制在JAVA中有什么区别?
【发布时间】:2025-11-28 18:15:02
【问题描述】:

我有一个问题——在递归函数 BT() 的基本条件中传递引用的这两种类型有什么区别? (在基础条件的 cmets 中提到)。

  1. https://ideone.com/rJP0Qv

import java.util.*;
public class Main
{
    public static void main(String[] args) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
 
        BT(res,temp,1,4,2);
        System.out.print(res);
    }
 
    public static void BT(List<List<Integer>> res,List<Integer> temp,int start , int n , int k ){
 
        if(temp.size()==k){
            res.add(temp);  // here we are just directly passing the temp refrence.
            return;
        }
 
        for(int i=start;i<=n;i++){
            temp.add(i);
            BT(res,temp,i+1,n,k);
            System.out.println("Temp "+temp);
            temp.remove(temp.size()-1);
 
        }
    }
}

  1. https://ideone.com/UtXsJa
import java.util.*;
public class Main
{
    public static void main(String[] args) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
 
        BT(res,temp,1,4,2);
        System.out.print(res);
    }
 
    public static void BT(List<List<Integer>> res,List<Integer> temp,int start , int n , int k ){
 
        if(temp.size()==k){
            res.add(new ArrayList(temp));  // here we are passing a new object in which temp reference is passed
            return;
        }
 
        for(int i=start;i<=n;i++){
            temp.add(i);
            BT(res,temp,i+1,n,k);
            System.out.println("Temp "+temp);
            temp.remove(temp.size()-1);
 
        }
    }
}

  1. 以上两个链接中的哪个在基本条件下具有临时列表的浅拷贝和深拷贝?

  2. 是不是因为我们在第一个链接 (https://ideone.com/MuLzLb) 中直接传递了参考 temp,所以我们在 temp 中所做的最后一次更改将在 List 中添加的所有结果中可见res ie [[], [], [], [], [], []] 因为 temp 在最后一次递归调用结束时将是一个空列表?

  3. 以及如何决定何时在递归函数中使用引用的深拷贝或浅拷贝?

【问题讨论】:

    标签: java reference deep-copy recurrence shallow-copy


    【解决方案1】:

    3.res.add(temp); ---> 浅拷贝 res.add(new ArrayList(temp)); ---> 深拷贝

    4.您的第一个代码 sn-p 给您空输出的原因是因为您只是在列表列表 (List res) 中添加引用,然后从引用中删除对象(temp ) 也是如此。所以最后 temp 将没有值,因此列表列表将没有值。

    如图所示 让我们假设 temp 有 [3,7,9] 并且当您添加 temp 时,只会传递它的引用,而不是副本。现在 [3,7,9] 将有 2 个引用。一个是 temp,另一个在 List的列表。 因此,每当您对 temp 进行任何更改时,它都会反映在 List res.

    5. 浅拷贝和深拷贝之间的选择没有硬性规定,但通常我们应该记住,如果对象只有原始字段,那么显然我们应该选择浅拷贝,但如果对象有引用到其他对象,那么根据需求,应该做浅拷贝或深拷贝。如果引用未修改,则没有必要启动深层复制

    注意:您的回溯算法涉及添加和删除列表中的值以获得不同类型的组合作为结果。因此,无论何时从引用中添加或删除值,您都应该复制它(如在第二个 sn-p 中完成)并将其存储在 List of Lists 中。

    【讨论】:

    • 感谢@Akash R 对我的查询进行了如此详细的解释。