当作为参数传递给返回 void 并在函数中修改的函数时,如何修改 Java ArrayList?可能对按值传递感到困惑

Posted

技术标签:

【中文标题】当作为参数传递给返回 void 并在函数中修改的函数时,如何修改 Java ArrayList?可能对按值传递感到困惑【英文标题】:How is a Java ArrayList modified when passed as parameter to function that returns void and modified in function? May be confused on pass-by-value 【发布时间】:2019-09-16 17:18:30 【问题描述】:

我有一个 Java 代码块,它通过将 ArrayList 传递给方法、修改方法中的列表并返回 void 来修改 ArrayList。我认为Java的按值传递会导致原始的ArrayList不被修改。我误会了什么?

public class Question 

    public static void weaveLists(LinkedList<Integer> first, LinkedList<Integer> second, ArrayList<LinkedList<Integer>> results, LinkedList<Integer> prefix) 
        /* One list is empty. Add the remainder to [a cloned] prefix and
         * store result. */
        if (first.size() == 0 || second.size() == 0) 
            LinkedList<Integer> result = (LinkedList<Integer>) prefix.clone();
            result.addAll(first);
            result.addAll(second);
            results.add(result);
            return;
        

        /* Recurse with head of first added to the prefix. Removing the
         * head will damage first, so we’ll need to put it back where we
         * found it afterwards. */
        int headFirst = first.removeFirst();
        prefix.addLast(headFirst);
        weaveLists(first, second, results, prefix);
        prefix.removeLast();
        first.addFirst(headFirst);

        /* Do the same thing with second, damaging and then restoring
         * the list.*/
        int headSecond = second.removeFirst();
        prefix.addLast(headSecond);
        weaveLists(first, second, results, prefix);
        prefix.removeLast();    
        second.addFirst(headSecond);
    

    public static ArrayList<LinkedList<Integer>> allSequences(TreeNode node) 
        ArrayList<LinkedList<Integer>> result = new ArrayList<LinkedList<Integer>>();

        if (node == null) 
            result.add(new LinkedList<Integer>());
            return result;
         

        LinkedList<Integer> prefix = new LinkedList<Integer>();
        prefix.add(node.data);

        /* Recurse on left and right subtrees. */
        ArrayList<LinkedList<Integer>> leftSeq = allSequences(node.left);
        ArrayList<LinkedList<Integer>> rightSeq = allSequences(node.right);

        /* Weave together each list from the left and right sides. */
        for (LinkedList<Integer> left : leftSeq) 
            for (LinkedList<Integer> right : rightSeq) 
//This is the part I don't understand
                ArrayList<LinkedList<Integer>> weaved = new ArrayList<LinkedList<Integer>>();
                weaveLists(left, right, weaved, prefix);
                result.addAll(weaved);
            
        
        return result;
    


我希望在调用 result.addAll(weaved) 时不会修改编织数组,但在调用 weaveLists() 之后会修改编织数组,即使它返回 void。

【问题讨论】:

这应该会有所帮助:javaranch.com/campfire/StoryCups.jsp, javaranch.com/campfire/StoryPassBy.jsp。 "但是编织数组在调用 weaveLists() 后被修改,即使它返回 void" 返回类型与方法参数在方法中的使用方式无关,我不知道你为什么不这样想。 【参考方案1】:

您创建了一个weaved 引用,该引用指向存储在内存中的ArrayList 对象。当您调用new 运算符时,会在内存中分配一个新对象。然后将引用 weaved 传递给 weaveLists() 方法。 这个方法有一个引用result,但这只是一个引用内存中同一个对象的引用,因为只有new操作符分配了新的内存。所以,weaveLists() 方法修改了你原来的 ArrayList。这是您应该了解的主要功能,建议您阅读pass-by-valuepass-by-reference之间的区别。

【讨论】:

【参考方案2】:

简单地回答这个问题 - 您误解了 Java 中的按值传递的含义

如果你传递一个对象(在这种情况下是列表)并操作它的元素而不改变它的引用,它就是你传递的同一个对象,对象(列表)本身没有任何改变,它有与传递给函数时的引用相同,但更改确实适用于任何被操作的元素。

在这种情况下按值传递仅意味着如果您在函数中创建给定列表的新实例然后对其进行操作 - 原始列表不会应用任何更改,因为它将被视为局部变量,而不是过了一关。

查看this 问题的热门答案,或者只是阅读一些与按值传递相关的Java 基础知识。使用 this 博客,或任何其他您可能更喜欢的。

【讨论】:

实际上,我不认为你的传值方式的例子很有帮助,因为如果代码复制并操作它,它不会影响传入的项目 no不管它是如何通过的。我想到的一种方式是,被调用的方法不能通过设计创建一个新对象并将其作为传入的参数之一返回;被调用方法创建的对象返回给调用者的唯一方法是将其作为方法的返回值返回。

以上是关于当作为参数传递给返回 void 并在函数中修改的函数时,如何修改 Java ArrayList?可能对按值传递感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给正则表达式构造函数,并在 String.matchAll 方法中使用 [重复]

我应该将啥对象传递给需要 Void 的函数!在参数中? (科特林)

当作为参数传递给方法时,ViewModel 没有从 POST 表单绑定

将多个参数传递给线程函数

将多值/数组 GET 参数传递给 Azure Function 并在 CosmosDB 中使用

将参数传递给子节点解析器函数