zoukankan      html  css  js  c++  java
  • 集合中的对象与引用

    前两天在刷题的时候遇到个有趣的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     }

    争取早日不再是一只菜鸡
  • 相关阅读:
    Spring的两种代理JDK和CGLIB的区别浅谈
    抽象 工厂模式
    Mybatis总结面试题
    java抽象工厂模式
    java工厂设计模式
    java单例设计模式
    lombok基本使用
    HTML
    select查询操作(重要)五
    mysql的DML语言(需要背下来)(四)
  • 原文地址:https://www.cnblogs.com/jchen104/p/14899774.html
Copyright © 2011-2022 走看看