Java中是值传递还是引用传递?

Java中是值传递还是引用传递?

引言

Java参数传递到底是值传递还是引用传递这个问题看似简单但是面试的时候经常会被问到,很多程序员的理解都不尽相同,如果没有仔细想过这个问题很大概率会模糊不清。

很多人认为Java中如果传递的参数是基本类型就是值传递,传递的是引用类型就是引用传递,经过下面的例子我们就能清楚的知道这种理解是错误的,实际上Java中参数的传递是值传递,不存在引用传递。

形参和实参

首先我们先来搞懂形参和实参的概念,方便后续理解。方法的定义可能会用到 参数,参数在程序语言中分为:

形参Parameter)是函数被调用时用于接收实参值的变量。在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。形参是虚拟变量,只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。

实参Argument)是在调用时传递给函数的参数,即传递给被调用函数的值。实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

public static void main(String[] args) {
        int a = 1;
        //a为实参
        printValue(a);
    }

    //b为形参
    public static void printValue(int b) {
        System.out.println(b);
    }

引用传递和值传递

值传递是将实际参数的值复制一份传递给形式参数。在方法执行过程中,对形式参数的修改不会影响到实际参数的值。

引用传递则是将实际参数的引用(也就是地址)传递给形式参数。此时,形式参数和实际参数都指向同一个存储空间,因此对形式参数的修改实际上也会影响到实际参数的值。

下面我们就根据代码示例来看一下Java中的参数传递:

  1. 传递基本类型参数
public static void main(String[] args) {
        int a = 2;
        leftShiftValue(a);
        System.out.println("a=" + a);
    }

    public static void leftShiftValue(int b) {
        b = b << 1;
        System.out.println("b=" + b);
    }
输出
b=4
a=2

leftShiftValue()方法中修改b的值并不会改变a的值,因为b的值是a的值复制过来的,b的值怎么修改都不会改变a原本的值,基本类型的参数传递也是比较清晰的证明是值传递,关键就是引用类型参数传递。

  1. 传递引用类型参数(形参值不变)
public static void main(String[] args) {
        Product product1 = new Product();
        product1.setName("产品1");
        change(product1);
        System.out.println("product1:" + product1.getName());
    }

    public static void change(Product product2) {
        product2.setName("产品2");
        System.out.println("product2:" + product2.getName());
    }
输出
product2:产品2
product1:产品2

可以看到change()方法中修改形参product2的名称属性为产品2,实参product1中的名称也改变了,是不是就证明Java中就是引用传递?其实不是,引用类型参数传递的是实参引用(地址)的拷贝,传递的也是一个值,只不过这个值是地址。

那为什么修改change()方法中修改product2中的字段属性值,实参product1中的字段属性值也改变了?这不是满足引用传递的定义对形式参数的修改实际上也会影响到实际参数的值吗?

那是因为在这个方法中,并没有对形参本身进行修改,而是修改的形参持有的地址中存储的内容。product2的值是product1地址的拷贝,修改的是product2引用指向中存储的内容,也就是说change()方法实际上并没有对形参product2的值进行修改,product1和product2的引用也就是地址始终都没有改变过,只不过修改了地址指向中的内容。

下面看一下引用类型参数传递真正改变形参的值的例子就能很好证明这一点。

  1. 传递引用类型参数(形参值改变)
    public static void main(String[] args) {
        Product product1 = new Product();
        product1.setName("产品1");
        change(product1);
        System.out.println("product1:" + product1.getName());
    }

    public static void change(Product product2) {
        Product newProduct = new Product();
        newProduct.setName("产品2");
        product2 = newProduct;
        System.out.println("product2:" + product2.getName());
    }
输出
product2:产品2
product1:产品1

在这里插入图片描述

这个change()方法中新建了个Product对象将新建的对象赋值给形参product2,然后打印形参和实参的值,我们发现形参的改变并没有导致实参的改变。

这个例子中形参product2的值(product1引用地址的拷贝)通过新建的对象赋值已经改变了,也就是说这里形参的值真正改变了,如果Java中是引用传递,那么实参product1中引用指向应该也被改变指向newProduct的地址才对,product1应该输出产品2才对。因为对形式参数的修改不会影响到实际参数的值,所以引用类型参数传递也是值传递。

总结

Java中参数的传递是值传递,无论基本类型和引用类型参数传递都会拷贝原有值,如果参数是基本类型传递的就是基本类型的字面值的拷贝,如果参数是引用类型,传递的就是实参所引用的对象在堆中地址值的拷贝,都会创建副本。

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值