1

I'm slightly confused how Java works, I know the following to be true:

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

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

We know c outputs 0 because the changeC method does not change the original c

Now I'm looking at a solution on Leetcode, and it seems to following a similar concept.

Here is the code:

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);
    }
}

In this case, the grid is passed to the void function dfsFills(). Yet, whatever dfsFill() does to grid, the grid in the numIslands() function is also updated.

Why does this act differently than my first example? Is one pass by reference and the other pass by value?

James Mitchell
  • 2,387
  • 4
  • 29
  • 59
  • 2
    Yes, you answered yourself correctly. The JVM passes along the call stack a reference to the memory area where the array elements are stored, while the primitive integer is copied. Mutable arrays (but I'd say objects in general) are dangerous to pass around, as at times you can't be sure about the side-effects produced by the called methods. That's why defensive-copy is used http://www.javapractices.com/topic/TopicAction.do?Id=15 – LppEdd Mar 09 '19 at 00:59

2 Answers2

1

It is not pass-by-reference, because no matter what happens inside the method, the variable grid of the caller still points to the same object it did before the call.

The difference is that grid is a mutable object (an array), so the method can cause the state inside of grid to change. Since both places (caller and callee) look at the same object, they will both see the changes made there.

Everything in Java is passed by value. But except for primitive types that "value" being passed is a pointer to an object. So if the state of that object is mutable, you need to be careful.

"Pass-by-reference" would mean that the method could change the variable of the caller to point at a different object. That is not possible. In your example you can be sure that e.g. grid is not suddenly null or that its length has changed.

Thilo
  • 257,207
  • 101
  • 511
  • 656
0

Yes and no.

Yes because that's how JVM internally works. Primitive parameters like int are passed by copying their value, while all other parameters like String or int[] are passed by copying a reference (points to the actual object in heap).

No because you will see exactly the same behavior even when you are using an java.lang.Integer, which is the boxed type of int and is passed by copying a reference. In fact, terms like "pass by value" and "pass by ref" are not used in java at all.

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

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

The key fact is i++ means i = i + 1, which use i and 1 to produce a new int, bind name i with that new int, and discard the previous int value, instead of mutating the previous int directly.

Things like array[0]++ or people.age++ work in the same way. It bind the property age of people with a new int. It changes the property age, but not affects the int itself

yyyy
  • 593
  • 2
  • 10