【问题标题】:Java - Parameter and Enhanced For Loop copy issueJava - 参数和增强的 For 循环复制问题
【发布时间】:2015-03-24 15:59:42
【问题描述】:

假设我有这样的代码;

public void insert(Student[] stus)
{
    int count = 0;
    for(Student s: stus)
    {
    s.setId( bla bla);
    stus[count].setId(bla bla) // is this line needed?
    count++;
    }
}

所以,如果我从增强的 for 循环中更改 s 上的任何内容,我还能看到 stus 数组的变化吗?增强的 for 循环复制在参数或其他方面如何工作?

【问题讨论】:

    标签: java foreach parameter-passing arrays


    【解决方案1】:

    增强的 for 循环不会创建您正在迭代的集合或数组元素的副本,因此 s.setId()stus[count].setId() 将更新相同的 Student 实例。

    stus[count].setId(bla bla) 不需要,s.setId(bla bla) 也是如此。

    【讨论】:

    • 增强的 for 循环对数组使用迭代器。见docs.oracle.com/javase/specs/jls/se8/html/…
    • 感谢您的时间和回答。那么它是否使用迭代器?
    • @JonSkeet 我不准确。 Iterator 在迭代 Iterable 时使用。在这个问题中,OP 正在迭代一个数组,所以没有迭代器。
    • @MertSerimer 如果stus 是一个Iterable(例如List 或Set),它会使用一个迭代器,但是由于它是一个数组,所以它不使用一个迭代器。
    【解决方案2】:

    是的 - s 只是一个包含从 stus 复制的值的变量。该值是对对象的引用 - 通过s 所做的更改仍将在stus 中可见。它只是被复制的reference。所以你的循环可以是:

    for (Student s : stus) {
        s.setId(...);
    }
    

    根本不需要count,除非它是 ID 计算的一部分。如果它 该计算的一部分,我将只使用常规 for 循环:

    for (int i = 0; i < stus.length; i++) {
        s.setId(/* some expression involving i */);
    }
    

    【讨论】:

    • 感谢您的时间和回答。好吧,如果需要那条线,那么我需要一个柜台。你会问为什么不使用普通的“for”?这是因为与增强的 for 相比,我懒得写那么长的语法
    • @MertSerimer:但是当您需要单独声明 count 然后递增它时,它不会更长。基本上,如果您需要知道您正在进行哪个迭代(并且您正在迭代一个数组),我建议您使用普通的for 循环。如果你不需要迭代次数,那么增强的for循环更简单,是的。
    【解决方案3】:

    stus 是对数组对象的引用,这意味着您在insert 中对其执行的任何更改都会影响实际参数(您用来调用insert 的变量)为以及其元素的变化。

    另一方面,您不需要count,因为s 已经是对迭代元素的引用:

    public void insert(Student[] stus)
    {
        for(Student s: stus)
        {
            s.setId( bla bla);
        }
    }
    

    【讨论】:

    • 感谢您的宝贵时间和回答。好吧,如果需要那条线,那么我需要一个柜台。你会问为什么不使用普通的“for”?这是因为与增强的 for 相比,我懒得写那么长的语法
    • Java 不使用传递引用,永远。引用是按值传递的。这与传递引用不同。特别是,如果您在 insert 方法中写入 stus = new Student[0];,那么调用者将可见,而它会通过真正的传递引用。
    • @JonSkeet 我假设出于所有目的,如果您通过值传递对象的引用,效果就像通过引用传递该对象。
    • @PabloFranciscoPérezHidalgo:这是一个不正确的假设——而且你的描述(当然,正如其他人所说的那样)是过去让许多习惯于真正的传递引用的人感到困惑的描述。重要的是要理解在 Java 中变量的值是从不一个对象。只是一个原语或一个参考。接下来,所有参数都按值传递——参数的初始值是参数值的副本。到那时,一切都很简单。
    • @JonSkeet 我知道 Java 中变量的值不是值本身,除非它是原始类型。您只能通过引用访问对象,当然,当您将对象作为参数传递时,其引用是按值传递的。但是,效果是,如果您在方法中更改对象,您将更改同一个对象,因为您复制的是引用而不是对象。效果就像通过引用传递对象,虽然它已经被引用了,但它是按值传递的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    • 2011-01-20
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多