Java 参数传递,值传递、地址传递

目录

起因

Java 参数传递规则

实际测试:

参考资料


起因

前两天一道题,看排名第一的题解把我难到了,当时百度好久没找到问题原因。今天突然思如泉涌,顺利解之。

原题目是LeetCode 200. 岛屿数量,解题思路也很简单,遇见一个岛屿“1”,就上下左右遍历把相连的“1”都变成“0”,然后把改变后的数组返回替换掉原数组,代码如下。

class Solution {
    public int numIslands(char[][] grid) {
        // dfs
        int m = grid.length,n = grid[0].length;
        int num = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j]=='1'){
                    num++;
                    grid = dfs(grid,i,j);
                }
            }
        }
        return num;
    }
    // (i,j) 上下左右往外扩散全变成 0
    public char[][] dfs(char[][] grid,int i,int j){
        int m = grid.length,n = grid[0].length;
        grid[i][j]=0;
        // 往左
        if (j>=1 && grid[i][j-1]=='1'){
            grid = dfs(grid,i,j-1);
        }
        // 往右
        if (j<n-1 && grid[i][j+1]=='1'){
            grid = dfs(grid,i,j+1);
        }
        // 往上
        if (i>=1 && grid[i-1][j]=='1'){
            grid = dfs(grid,i-1,j);
        }
        // 往下
        if (i<m-1 && grid[i+1][j]=='1'){
            grid = dfs(grid,i+1,j);
        }
        return grid;
    }
}

但是看完题解我懵了,直接用的void 函数上下左右遍历。参数传递不是值传递吗?void返回空原函数不是不会改变吗?难道是void和数组结合有特定的效果?但是百度一通也没找到合适的答案。

class Solution {
    public int numIslands(char[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }
        int nr = grid.length;
        int nc = grid[0].length;
        int num_islands = 0;
        for (int r = 0; r < nr; ++r) {
            for (int c = 0; c < nc; ++c) {
                if (grid[r][c] == '1') {
                    ++num_islands;
                    dfs(grid, r, c);
                }
            }
        }
        return num_islands;
    }
    // DFS扫描整个二维网格。如果一个位置为 1,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。
    void dfs(char[][] grid, int r, int c) {
        int nr = grid.length;
        int nc = grid[0].length;
        if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
            return;
        }
        grid[r][c] = '0';
        // 上
        dfs(grid, r - 1, c);
        // 下
        dfs(grid, r + 1, c);
        // 左
        dfs(grid, r, c - 1);
        // 右
        dfs(grid, r, c + 1);
    }
}

然后今天看文章偶然看到“地址传递”,瞬间想到了这个题目。之前一直理解的“值传递”只是单纯的数值传输。其实并不一定,数组在函数传递没法传递值,只能把数组在内存中的地址作为值传递,这样一想问题就迎刃而解了。

Java 参数传递规则

Java 的参数本质上都是以值传递的形式传入方法中,而不是引用传递。但是值传递应该分两种(值传递、地址传递):

1.当参数是Java基本类型时,传递的参数是值的拷贝,原值不会随之变动。此时是单纯的数值传递

由于栈中存的就是“实际值”(java基本类型的值存储在栈中,不在堆中),所以传递的是基本类型的“实际值”的拷贝。

2.当参数是引用类型(对象、数组等)时候,传递的是对象或者数组所引用的地址,改变传递值就是改变原值。此时是对象在内存中的地址以值的方式传递到形参

由于栈中存的是地址(该地址指向堆内存中存储位置,即引用),所以传递的是“堆中的地址”的拷贝。所以我们说成是“引用(址)传递”。

注意:
1. “String和8大基本类型的包装类”是不可变类型,即特殊的引用类型。每次修改操作都会新生成一个对象并重新赋给引用,栈中的地址会不断更换,所以出现了不能修改值的效果,看起来像是值传递了。
2. 而一般对我们自己创建的类进行修改操作,就会顺着引用的地址“找到并修改掉”原来的值,所以达到了引用传递的效果。

实际测试:

第一种很好理解,比如说传递个int 5,第二种就适合撸代码测试下。

package dope;
// public class Dog {
//     String name;

//     Dog(String name) {
//         this.name = name;
//     }

//     String getName() {
//         return this.name;
//     }

//     void setName(String name) {
//         this.name = name;
//     }
// }

class Test{
    public static void main(String[] args) {
        Dog dog = new Dog("A");
        System.out.println(dog.toString());
        change(dog);
        System.out.println(dog.getName());
    }

    private static void change(Dog dog) {
        System.out.println(dog.toString());
        dog.setName("B");
    }
}

输出结果:

dope.Dog@15db9742
dope.Dog@15db9742
B

显然main函数和change函数中 dog 对象的地址没有改变,是同一个对象,name结果是 B。参数传递的是“地址值”,在change方法中改变对象的值会改变原函数中对象该值。

参考资料

Java是“按引用传递”还是“按值传递”?

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值