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

Java列表使用异常:添加子列表后元素值意外变动问题排查

问题:List<List>中子列表值意外变动的原因分析

问题现象

向List<Integer>添加元素后将其加入List<List<Integer>>,但子列表的值在添加后立即发生意外变动。使用普通for循环替代foreach问题依旧,仅当在result.add()中通过new ArrayList<>(o)初始化新列表时,问题消失。

相关代码片段

List<List<Integer>> c2 = sum(rs, target - i);
System.out.println(c2);

for (List<Integer> o : c2) {
    System.out.println(result);
    result.add(o);
    result.get(result.size()-1).add(i);
    System.out.println(result);
}

输出对比

原始输出(直接add(o))

[[1]]
[]
[[1, 1]]
[[1]]

修改后输出(使用new ArrayList<>(o))

[[1]]
[]
[[1, 1]]
[[1, 1]]

底层原因

核心问题在于Java中对象的引用传递机制:

  • 当执行result.add(o)时,并没有复制o列表的内容,而是将o的内存引用直接存入result。这意味着result中的子列表和c2中的o指向的是同一个List对象。
  • 后续调用result.get(result.size()-1).add(i)时,本质是在修改这个共享的List对象。如果该对象还被其他地方(比如递归栈中的返回结果、原始输入列表)持有引用,那么其他地方对该对象的修改也会同步反映到result中,导致你看到的“意外变动”。
  • 再看递归的base case代码:result.add(candidates);这里直接将传入的candidates列表引用加入结果,而candidates可能是上层方法中rs的原始引用(rs是candidates的副本,但base case中的candidates是rs本身),后续上层循环对rs的操作或其他递归调用可能间接修改这个共享对象,进一步加剧了值的异常变动。
  • 当改用result.add(new ArrayList<>(o))时,会创建一个全新的List对象,并复制o中的所有元素。此时result中的子列表是独立的新对象,和原来的o没有引用关联,修改新对象不会影响其他地方的列表,问题自然解决。

完整代码

import java.util.*;
import java.util.stream.*;

public class Solution {
    public static void main(String[] args) {
        (new Solution()).combinationSum2(new int[]{1,1}, 2);
    }
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<Integer> s = IntStream.of(candidates).boxed().map(i -> i).sorted().collect(Collectors.toList());

        return sum(s, target);

    }

    private List<List<Integer>> sum(List<Integer> candidates, int target) {
        List<List<Integer>> result = new ArrayList<>();
        if (candidates.size() == 1) {
            if (candidates.get(0) == target) {
                System.out.println("found as single element");
                result.add(candidates);
            }
            return result;
        }
        
        Integer last = null;
        List<Integer> rs = new ArrayList<>(candidates);
        for (int i : candidates) {
            rs.remove(0);
            if (last != null && last == i)
                continue;
            if (i == target) {
                List<Integer> tmp = new ArrayList<>(1);
                tmp.add(target);
                result.add(tmp);
            }

            List<List<Integer>> c2 = sum(rs, target - i);
            System.out.println(c2);
            for (List<Integer> o : c2) {
                System.out.println(result);
                result.add(o);
                result.get(result.size()-1).add(i);
                System.out.println(result);
            }
            last = i;
        }

        System.out.println(result);
        return result;
    }
}

内容的提问来源于stack exchange,提问作者A. Johnston

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:55:35