在递归调用期间,方法的参数如何存储在堆栈中?

How does parameters of a method get stored in stack during a recursive call?

我在做一道 leetcode 题 https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree-ii/,我对在递归调用期间如何存储方法的参数感到困惑。

如果访问了一个节点,我想保存它被访问时的状态。当我发送两个变量时,当堆栈展开时,更新的变量值将丢失。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        boolean val1 = false, val2 = false;
        System.out.println("val1 - "+val1+" val2 - "+val2);
        System.out.println();

        TreeNode node = lca(root, p, q, val1, val2);
        System.out.println();
        System.out.println("val1 - "+val1+" val2 - "+val2);

        if(val1==true && val2==true)
            return node;
        return null;
    }
    
    private TreeNode lca(TreeNode root, TreeNode p, TreeNode q, boolean val1, boolean val2) {
        if(root==null) 
            return root;
        else if( p==root){
            val1 = true;
            System.out.println("val1 - "+val1+" val2 - "+val2);
            return root;
        } 
        else if( root==q){
            val2 = true;
            System.out.println("val1 - "+val1+" val2 - "+val2);
            return root;
        } 

        TreeNode left = lca(root.left, p, q, val1, val2);
        TreeNode right = lca(root.right, p, q, val1, val2);
        
        if(left==null && right==null) return null;
        else if(left==null) return right;
        else if(right==null) return left;
        else return root;
    }
}

Output -
val1 - false val2 - false

val1 - true val2 - false
val1 - false val2 - true

val1 - false val2 - false

但是,如果我发送一个数组并更新数组内的值,并在递归期间将数组本身作为参数传递,那么更新后的变量值将被保留。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        boolean res[] = new boolean[2];
        //boolean val1 = false, val2 = false;
        System.out.println("val1 - "+res[0]+" val2 - "+res[1]);
        System.out.println();

        TreeNode node = lca(root, p, q, res);
        System.out.println();
        System.out.println("val1 - "+res[0]+" val2 - "+res[1]);

        if(res[0]==true && res[1]==true)
            return node;
        return null;
    }
    
    private TreeNode lca(TreeNode root, TreeNode p, TreeNode q, boolean res[]) {
        if(root==null) 
            return root;
        else if( p==root){
            res[0] = true;
            System.out.println("val1 - "+res[0]+" val2 - "+res[1]);
            return root;
        } 
        else if( root==q){
            res[1] = true;
            System.out.println("val1 - "+res[0]+" val2 - "+res[1]);
            return root;
        } 

        TreeNode left = lca(root.left, p, q, res);
        TreeNode right = lca(root.right, p, q, res);
        
        if(left==null && right==null) return null;
        else if(left==null) return right;
        else if(right==null) return left;
        else return root;
    }
}

Output - 

val1 - false val2 - false

val1 - true val2 - false
val1 - true val2 - true

val1 - true val2 - true

我觉得我在这里缺少一些基本知识,任何人都可以帮助我理解这两个代码有何不同以及任何material我可以阅读以提高我在堆栈和递归方面的知识吗?

这个问题与“递归”关系不大,而与函数调用本身有关。

当您调用 foo(var1, var2) 时,变量得到 passed by value。您在函数块内所做的更改不会传播到函数外。

当你传递数组时,它得到passed by reference/指针。对其进行的任何修改都是对它的实际内存进行的,因此即使在功能块之外,更改也会 retained/reflected。

您可以详细了解按值传递和引用传递之间的区别 here

编辑:
Java 是“始终”pass-by-value 因为对象具有按值传递的引用。 here 详细阐明了这个令人困惑的术语。