【问题标题】:Passing ArrayList as value only and not reference仅将 ArrayList 作为值而不是引用传递
【发布时间】:2013-03-24 14:31:37
【问题描述】:

简单地说,我有一个带有 ArrayList 参数的方法。在该方法中,我修改 ArrayList 的内容仅与该方法返回的内容相关。因此,我不希望作为参数传递的 ArrayList 受到影响(即不作为引用传递)。

我尝试的一切都未能达到预期的效果。我需要做什么才能仅在方法中使用 ArrayList 的副本,而不是让它更改实际变量?

【问题讨论】:

  • 您可以通过Collections#unmodifiable(yourList) 发送一份不可修改的列表副本。
  • 您还可以在修改它的方法中创建ArrayList 的新副本。虽然它不会影响第一个 ArrayList,但您在其中更改的任何对象仍将被更改...
  • 您只修改列表吗?或者还有什么在列表里面?
  • 有谁知道 System.arraycopy 是否只会复制引用或克隆数组中的对象?我找了源头,因为它是一个原生方法而结束了..

标签: java reference arraylist pass-by-reference


【解决方案1】:

在现有答案的行中,但使用 ArrayList API。您可以使用subList(fromIndex, toIndex) 方法。它显式地创建仅包含所需元素的列表视图(当然,按顺序)。在这里,即使你用添加/删除等操作修改了视图,它也不会改变原来的列表。它使您免于显式创建副本。

类似这样的:

public void recursiveMethod(List<Integer> list) {
    if(base)
         return;
    recursiveCall(list);

    // following will just create a tail list but will not actually modify the list
    recursiveCall(list.subList(1, list.size());
}

【讨论】:

    【解决方案2】:

    即使您有办法将数组列表作为副本而不是通过引用传递,它也只是一个浅拷贝。

    我会这样做:

    void foo(final ArrayList list) {
    
        ArrayList listCopy = new ArrayList(list);
        // Rest of the code
    
    }
    

    只需在复制的列表上工作。

    【讨论】:

    • 就可以了。我最初尝试将内部列表设置为等于参数,但这不起作用。这是迄今为止最简单的解决方案。
    • 确实,需要等待一段时间才能接受答案。
    • 当你有对象列表时它不起作用!通过更改对象,因为它们不是最终的,列表也发生了变化。
    【解决方案3】:

    我不知道为什么,即使在new ArrayList&lt;MyObj&gt;(old) 之后,该对象仍在不应该更改的地方更改引用。所以我不得不实例化里面的对象的一个​​新副本。

    我创建了一个复制构造函数,就像 ArrayList 上的那个一样

     newArray = new ArrayList<MyObj>();
            for (int i = 0; i < oldArray.size(); i++) {
                newArray.add(new MyObj(ondArray.get(i)));
            }
    

    如果 Avi 的回答对你来说还不够,只是希望能帮助别人,比如我的代码太乱,甚至无法理解 =P

    【讨论】:

      【解决方案4】:

      在你的方法中试试这个:

      void method(List<Integer> list) {
              List copyList =  new ArrayList<Integer>();
              copyList.addAll(list); // This will create a copy of all the emlements of your original list
          }
      

      【讨论】:

      • 更好的是new ArrayList&lt;Integer&gt;(list)
      【解决方案5】:

      您可以使用 ArrayList 的复制构造函数创建 ArrayList 的副本:

      ArrayList copy = new ArrayList(original);
      

      但是如果列表的元素也是对象,那么你必须知道修改副本的成员也会修改原始成员。

      【讨论】:

      • 您将如何做到修改副本成员不会修改原始列表?
      【解决方案6】:

      克隆它。

      public ArrayList cloneArrayList(ArrayList lst){
          ArrayList list = new ArrayList();
          for (int i=0; i<lst.size(); i++){
              list.add(lst.get(i));
          }
          return list;
      }
      

      在cmets中添加建议,也可以使用

      ArrayList copy = new ArrayList(original);
      

      还有

      ArrayList copy = new ArrayList();
      copy.addAll(original);
      

      【讨论】:

      • 恕我直言,这似乎太过分了,new ArrayList(list) 有什么问题?
      • 我不知道new ArrayList(list)的存在。对不起。
      • @SriHarshaChilakapati 不要因为学习新东西而感到抱歉
      【解决方案7】:

      您可以通过Collections#unmodifiableList(yourList) 发送一份不可修改的列表副本。顺便说一句,您的List&lt;Whatever&gt; 是从Java always pass by value 开始按值传递的,请注意,在foo(List&lt;Whatever&gt; list) 方法中,您不能修改list 的值,但您可以修改其内容

      public class MyClass {
      
          List<Whatever> list = new ArrayList<Whatever>();
      
          public void bar() {
              //filling list...
              foo(Collections.unmodifiableList(list));
          }
      
          public void foo(List<Whatever> list) {
              //do what you want with list except modifying it...
          }
      }
      

      【讨论】:

        【解决方案8】:

        您可以使用.clone 方法或CopyOnWriteArrayList 进行复制,从而不会影响原件。

        【讨论】:

        • 恕我直言,这似乎太过分了,new ArrayList(list) 有什么问题?
        • 恕我直言 =“在我看来”
        猜你喜欢
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 2018-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-11
        相关资源
        最近更新 更多