图解Java参数传递

本文探讨了Java中参数传递的原理,通过程序示例和流程图解释了基本类型和引用类型参数传递的区别。对于基本类型,Java采用值传递,不会影响原始变量;而对于引用类型,实际上是引用传递,函数内部对参数的修改会影响到原始变量。通过final关键字可以限制对引用类型参数的修改。
摘要由CSDN通过智能技术生成

Title: 图解Java参数传递
Date: 2018-11-27 12:30
Category: 技术博客
Modified: 2018-11-27 12:30
Tags: Java
Slug: JavaParaPass
Authors: Victor Lv
Summary: 先学过 C/C++ 然后再学 Java 的同学们都会有一个疑问,C/C++里面 的参数传递分为值传递指针传递引用传递,Java 中不存在指针,自然不存在指针传递,那么 Java 的参数传递是值传递还是引用传递?抑或是二者都有?

先学过 C/C++ 然后再学 Java 的同学们都会有一个疑问,C/C++里面 的参数传递分为值传递指针传递引用传递,Java 中不存在指针,自然不存在指针传递,那么 Java 的参数传递是值传递还是引用传递?抑或是二者都有?

本文将以程序示例和自拟的流程图来讲解这个问题。

程序示例:

    public static void passTest1(int i) {
        i = 0;
    }

    public static void passTest2(int[] ints) {
        ints[0] = 0;
    }

    public static void main(String[] args) {

        int i = 1;
        System.out.println(i);
        passTest1(i);
        System.out.println(i);

        int[] ints = new int[]{1,2};
        System.out.println(ints[0]);
        passTest2(ints);
        System.out.println(ints[0]);

        /**
         * Output:
         1
         1
         1
         0
         */
}

可以发现传递基本类型的参数时,并没有函数外面原有变量的值;而如果传的是复杂类型(引用类型),比如数组或者 Object ,那么针对传进来的参数的内容修改,也会反映到函数外原有变量。

下面用流程图的方式描述下我对于 Java 参数传递的理解:

基本类型传参——值传递

基本类型传参流程图

基本类型传参

对应的程序:

public static void passTest3(int i1, int i2) {
        i1 = i1 + i2;
    }
    
int i1 = 1;
int i2 = 2;
passTest3(i1, i2);
System.out.println(i1);
/**
Output:
1
*/

如图,对于基本类型参数传递,系统会将把源参数(实际参数)的内容取出来,放进(中间省略了内容传递的中间流程) CPU 缓存区,有内容则必有载体,所以这个过程中间,肯定会在一个新的内存地址中存放源参数的内容(形式参数),也就是产生了一份内容副本,但是内存地址(假设是地址B)已经和源参数(假设是地址A)的不一样了。

然后基于这两个副本的值,CPU对其做加法运算,得出一个新的值作为内容存进了地址B中。

内容副本复制完成之后,就没**源参数(地址A)什么事了,所以自然也不会修改源参数(地址A)**里面的值了。

复杂类型(引用类型)传参——引用传递

复杂类型传参流程图

复杂类型传参

对应的程序:

    public static void passTest4(int[] ints, int i) {
        ints[0] = ints[0] + i;
    }
    
    int[] ints = new int[]{1,2};
    int i = 6;
    System.out.println(ints[0]);
    passTest4(ints, i );
    System.out.println(ints[0]);

    /**
    * Output:
    1
    7
    */

如图,对于复杂类型的参数传递,如果这个复杂类型的内容特别大,总不能把这么大的内容都挪出来做一个副本然后放到缓冲区吧?所以很自然地就产生了一个方法,就是:你给我一把钥匙(引用),钥匙上写着门房地址,回头我自己去这个门房地址把我要的东西取出来。

所以对于复杂类型的参数传递,传递的实际是该参数的引用(存放地址【假设是地址A】的变量),传递进来的是引用,那么函数内操作的就是实参的地址/内容了,对这个参数的取值和修改都是直接作用于地址A。比如 ints[0]实际是通过引用去到地址A所在的堆栈空间中,取出其子元素(假设是地址A1)。在做完加法运算后,又把运算结果存到的地址A1中。于是,我们发现,地址A里面的内容已经变了(因为它里面的子地址A1的内容变了)。

所以,在复杂类型的参数传递中,有一个风险就是,我把钥匙和门房地址都给你了,那我房间的东西岂不是任你使用,并且也任你“糟蹋”(修改)?所以我们可以通过final关键字,告诉系统:你可以看但不能动我房间里面的东西,此所谓“可远观而不可亵玩焉”。

更深入的讲解可以看看这篇参考资料:

参考资料:
Java 到底是值传递还是引用传递?知乎 Intopass 的回答

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值