集合中的对象与引用

前两天在刷题的时候遇到个有趣的BUG,提醒了自己还是基础不牢固,这里记录一下

错误代码是这样的

 1 public void backtrack(int n, List<Integer> output, List<List<Integer>> res, int first) {
 2         if (first == n) {
 3             res.add(output);
 4         }
 5         for (int i = first; i < n; i++) {
 6             Collections.swap(output, first, i);
 7             backtrack(n, output, res, first + 1);
 8             Collections.swap(output, first, i);
 9         }
10     }

这是一段回溯的代码,我们不断的修改集合output的值,并

利用res记录下来每一种结果。

但是最后发现res中的结果全部一致,比对了正确答案发现应该写成

res.add(new ArrayList<Integer>(output));

于是我又去查阅了下相关资料,发现其实我们很容易忽略集合本身也是对象

ArrayList的定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

集合中存储的是对象本身而非引用,上面的错误代码里res里存储的是output这个引用指向的对象。

output引用指向的对象一直是固定的,因此造成了实际上的对象内容的变化,最终造成的效果是res虽然

看起来压入了不同状态下的output,但由于他们都是同一个对象,因此最后res的结果全部是一致的。

这里给出一组参考样例

 1     public static void main(String[] args){
 2         List<Integer> l1 = new ArrayList<Integer>();
 3         List<List<Integer>> l2 = new ArrayList<List<Integer>>();
 4         Integer a = 1;
 5         l1.add(a);
 6         l2.add(l1);
 7         System.out.println(l1);
 8         System.out.println(l2);
 9         // 引用a指向了新的对象,旧的对象并未变化,因此l1未变
10         a = 2;
11         System.out.println(l1);
12         // 引用l1还是指向原来的对象,该对象产生了变化,因此l2变了
13         l1.add(a);
14         System.out.println(l2);
15     }

争取早日不再是一只菜鸡
原文地址:https://www.cnblogs.com/jchen104/p/14899774.html