在 void 方法 [duplicate] 之后更新 Java 变量

Java variables updating after void method [duplicate]

提问人:James Mitchell 提问时间:3/9/2019 更新时间:3/9/2019 访问量:3162

问:

我对 Java 的工作原理有点困惑,我知道以下几点是正确的:

public static void main(String[] args) {
    int c=0;
    changeC(c);
    System.out.println(c); // 0
}

public static void changeC(int c) {
    c++;
}

我们知道输出,因为该方法不会改变原来的c0changeCc

现在我正在研究 Leetcode 上的解决方案,它似乎遵循类似的概念。

代码如下:

public int numIslands(char[][] grid) {
    int count=0;
    for(int i=0;i<grid.length;i++)
        for(int j=0;j<grid[0].length;j++){
            if(grid[i][j]=='1'){
                dfsFill(grid,i,j);
                count++;
            }
        }
    return count;
}
private void dfsFill(char[][] grid,int i, int j){
    if(i>=0 && j>=0 && i<grid.length && j<grid[0].length&&grid[i][j]=='1'){
        grid[i][j]='0';
        dfsFill(grid, i + 1, j);
        dfsFill(grid, i - 1, j);
        dfsFill(grid, i, j + 1);
        dfsFill(grid, i, j - 1);
    }
}

在这种情况下,网格被传递给 void 函数。然而,无论对 做什么,函数中的函数也会更新。dfsFills()dfsFill()gridgridnumIslands()

为什么这与我的第一个示例不同?一个是按引用传递,另一个是按值传递吗?

Java 方法 参数传递 引用

评论

2赞 LppEdd 3/9/2019
是的,你回答正确。JVM 沿调用堆栈传递对存储数组元素的内存区域的引用,同时复制原始整数。可变数组(但我想说的是一般的对象)传递起来很危险,因为有时你无法确定被调用方法产生的副作用。这就是为什么在 javapractices.com/topic/TopicAction.do?Id=15 使用防御性复制的原因

答:

0赞 yyyy 3/9/2019 #1

是的,也不是。

是的,因为这就是 JVM 内部的工作方式。基元参数(如)通过复制其值来传递,而所有其他参数(如 或)通过复制引用(指向堆中的实际对象)来传递。intStringint[]

否,因为即使您使用 ,您也会看到完全相同的行为,这是 的盒装类型,并通过复制引用来传递。事实上,像 “pass by value” 和 “pass by ref” 这样的术语在 java 中根本没有使用。java.lang.Integerint

void foo() {
  Integer i = 0;
  bar(i);
  assert i == 0;
}

void bar(Integer i) {
  i++;
}

关键事实是 means ,它使用并生成一个新的 ,将名称与该新名称绑定,并丢弃前一个值,而不是直接改变前一个值。i++i = i + 1i1intiintintint

类似或以同样的方式工作。它将 的属性与新的 .它改变了属性,但不影响它本身array[0]++people.age++agepeopleintageint

1赞 Thilo 3/9/2019 #2

它不是按引用传递的,因为无论方法内部发生什么,调用方的变量仍然指向它在调用之前执行的相同对象。grid

不同之处在于它是一个可变对象(数组),因此该方法可以导致 of 内部的状态发生变化。由于两个位置(调用方和被调用方)都查看同一个对象,因此它们都将看到在那里所做的更改。gridgrid

Java 中的所有内容都是按值传递的。但是,除了基元类型之外,传递的“值”是指向对象的指针。因此,如果该对象的状态是可变的,则需要小心。

“Pass-by-reference”意味着该方法可以更改调用方的变量以指向不同的对象。这是不可能的。在您的示例中,您可以确定例如 不是突然的,也不是它的长度发生了变化。gridnull