【问题标题】:Changes to one object inadvertently changes another object对一个对象的更改无意中更改了另一个对象
【发布时间】:2020-07-16 02:06:07
【问题描述】:

我正在尝试使用 java 中的列表,但我的代码中出现以下错误(见下文)。我创建了一个新的列表对象 L1 并将其传递给函数 f。在函数 f 中,我创建了 L1 的副本并将其命名为 L2。我在 L2 上执行添加操作并从函数返回。在我返回后,L1 的值发生了变化。怎么会这样?据我了解,L1 的范围并未扩展到函数 f,因此无法在函数 f 中更改 L1。 L2 是 L1 的副本,并且是它自己的对象,因此对它的任何更改也不应该更改 L1。谁能给我解释一下?

import java.util.List;
import java.util.ArrayList;

public class HelloWorld{

     public static void main(String []args){
        List<String> L1 = new ArrayList<String>();
        L1.add("H");
        L1.add("I");
        System.out.println(L1);
        
        f(L1);
        
        System.out.println(L1);
     }
     
     public static void f(List<String> myList){
         List<String> L2 = new ArrayList<String>();
         L2 = myList;
         
         L2.add("!");
         return;
     }
}

打印出来的

[H, I]
[H, I, !]

【问题讨论】:

  • 你没有返回列表并将其设置为L1

标签: java list object


【解决方案1】:

问题是您正在创建一个新的ListL2,然后用L2 = myList 覆盖引用,您应该添加来自myList 的每个String 值。试试这个。

public static void f(List<String> myList) {
    List<String> L2 = new ArrayList<>();
    for(String str : myList) L2.add(str);
    L2.add("!");
}

由于List 是一个对象,它作为对方法f 的引用传递,因此如果您使用L2 = myList,您只是说L2 指向与myList 相同的List。阅读更多here

您也不必在void 方法中显式地return

最后请注意,您的方法 f 并没有真正做太多事情,因为它只会创建一个本地新的 List 而您不会返回它。

【讨论】:

  • 我实际上是为了解决它。我仍然对它为什么会覆盖它感到困惑。它们不是两个不同的对象吗?编辑:好的,我会看看链接。这是从实际执行某些操作的较大代码中抽象出来的示例,
  • 是的,但是当您执行L2 = myList 时,L2 的先前值被“丢弃”。它只是变量重新分配。
  • 啊,这是 java 特有的东西吗?还是出现在其他语言中?
  • 它出现在其他语言中很正常,就像一个简单的int。如果你有int a=2, b=3 并且你有b=a 值3 是“丢失”。对象也是如此,但变量保存的是引用而不是原始值。
【解决方案2】:

传入的列表不是列表的副本,它是一个引用,它指向列表。

您将一个列表的引用传递给一个方法,该引用仍然指向原始列表 L1。然后将它分配给 L2,现在 L2 指向原始列表。所以不,您不会无意中更改第二个对象,它是同一个对象。

您可以将引用传递给方法,它仍然指向它指向该方法之外的同一个对象。

这对于按值传递引用的语言来说是正常的。 C、JavaScript 和 Lisp 的行为都与此类似。

【讨论】:

  • 谢谢你。我怀疑这一点,但我不知道这是通常的行为,因为我通常将原语传递给函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 2012-05-14
  • 1970-01-01
  • 2013-03-23
相关资源
最近更新 更多