【问题标题】:Java ArrayList of ArrayListJava ArrayList 之 ArrayList
【发布时间】:2014-09-28 15:29:43
【问题描述】:

以下代码输出

[[100, 200, 300], [100, 200, 300]]. 

但是,我期望的是

[[100, 200, 300], [100, 200]], 

我哪里错了?

public static void main(String[] args) {
    ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> inner = new ArrayList<Integer>();        

    inner.add(100);     
    inner.add(200);

    outer.add(inner);
    outer.add(inner);

    outer.get(0).add(300);

    System.out.println(outer);

}

【问题讨论】:

  • 尝试使用outer.add(new ArrayList&lt;String&gt;(inner));

标签: java arraylist


【解决方案1】:

您正在向外部列表添加对同一内部ArrayList 的引用两次。因此,当您更改内部列表(通过添加 300)时,您会在“两个”内部列表中看到它(实际上只有一个内部列表,其中两个引用存储在外部列表中)。

为了得到你想要的结果,你应该创建一个新的内部列表:

public static void main(String[] args) {
    ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> inner = new ArrayList<Integer>();        

    inner.add(100);     
    inner.add(200);
    outer.add(inner); // add first list
    inner = new ArrayList<Integer>(inner); // create a new inner list that has the same content as  
                                           // the original inner list
    outer.add(inner); // add second list

    outer.get(0).add(300); // changes only the first inner list

    System.out.println(outer);
}

【讨论】:

    【解决方案2】:

    这就是你现在拥有的

    ArrayList<ArrayList<Integer>> outer = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> inner = new ArrayList<Integer>();        
    

    将创建

    outer -> []
    inner -> []
    

    之后

    inner.add(100);     
    inner.add(200);
    

    你的情况看起来像

    outer -> []
    inner -> [100, 200]
    

    令人困惑的部分来了

    outer.add(inner);
    outer.add(inner);
    

    实际上复制了 inner 引用的值,这意味着它们指向来自 inner 的相同列表

    outer -> [ reference1 , reference2 ]
                  |             |
          +-------+             |
          +---------------------+
          ↓
    inner +-> [100, 200]
    

    这意味着如果您更改inner 持有的列表状态,您将能够使用reference1 和reference2 看到这些更改。如果您通过其他引用更改此列表,则相同,因此当您使用

    outer.get(0).add(300);
    

    get(0) 返回列表,您也可以通过inner 或get(1) 访问该列表并添加新元素,所以现在情况看起来像

    outer -> [ reference1 , reference2 ]
                  |             |
          +-------+             |
          +---------------------+
          ↓
    inner -> [100, 200, 300]
    

    这就是为什么当你打印 outer 时你会看到

    [[100, 200, 300], [100, 200, 300]]. 
     ^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^
       from get(0)      from get(1)
    

    您真正需要的是创建单独的列表,这样reference1 和reference2 将指向两个单独的列表。所以你需要类似的东西

    outer  -> []
    inner1 -> [100, 200]
    inner2 -> [100, 200]
    

    后面会整理到

    outer -> [ reference1 , reference2 ]
                  |             |
           +------+             |
           ↓                    |
    inner1 -> [100, 200]        |
                                |
           +--------------------+
           ↓
    inner2 -> [100, 200]
    

    你可以这样做

    List<List<Integer>> outer = new ArrayList<List<Integer>>();
    List<Integer> inner1 = new ArrayList<Integer>();
    List<Integer> inner2 = new ArrayList<Integer>();
    
    inner1.add(100);
    inner1.add(200);
    
    inner2.add(100);
    inner2.add(200);
    
    outer.add(inner1);
    outer.add(inner2);
    
    outer.get(0).add(300);
    
    System.out.println(outer);
    

    【讨论】:

    • 视觉就是一切
    • 非常漂亮的可视化效果,为此 +1!但是有一个小错字:应该是from get(**1**) 而不是from get(**2**)。
    • @winklerrr 谢谢。更新了:)
    【解决方案3】:

    outer.add(inner) 命令向inner 添加一个引用,而不是它的副本。

    因此,当您将两个对 inner 的引用添加到 ArrayList outer 时,您添加了两个相同的东西。修改inner 到outer.get(0) 也会修改outer.get(1) 中的值,因为它们指的是同一个东西。

    如果您创建inner 的副本并改用它,那么您将拥有两个不同的实例并且能够分别修改它们。你可以用一个简单的命令来做到这一点:

    outer.add(new ArrayList<[var type]>(inner));
    

    new ArrayList(inner) 的指令创建一个 new ArrayList,其中包含 inner 的内容 - 但不使用与 inner 相同的实例。因此,您将保留内容,但不会保留重复的引用。

    通过添加新副本而不是引用,您可以修改副本而不修改您可能称之为“原始”的内容。

    【讨论】:

      【解决方案4】:

      在 IDE 中试试这个例子:

      ArrayList<ArrayList<String>> ext = new ArrayList<ArrayList<String>>();
          String[] arr = {"1","2","3","4","5","6"};
          int n=arr.length;
          for(int i=0;i<n;i++){
              ArrayList temp = new ArrayList<String>();
              for(int j=i;j<n;j++){
                  temp.add(arr[j]);
                  // this the line that needs to look at. Rather than pointing to the same memory reference creating a new ArrayList will store it in a different memory location. If you just add temp then it will point to same memory location.
                  ext.add(new ArrayList<String>(temp));
                   // Comment above line and uncomment below to see the difference    
                  //ext.add(temp);
              }
      
          }
          System.out.println(ext);
      

      【讨论】:

        猜你喜欢
        • 2017-04-08
        • 2015-06-22
        • 2012-05-27
        • 2012-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多