博客
关于我
【Java思考】Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?
阅读量:401 次
发布时间:2019-03-06

本文共 2993 字,大约阅读时间需要 9 分钟。

科普:

  • 值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
  • 引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
值传递 引用传递
根本区别 会创建副本(Copy) 不创建副本,直接引用
效果 函数中无法改变原始对象 函数中可以改变原始对象

Java 中的实参与形参之间的传递到底是值传递还是引用传递呢?

其实之前我和大多数人一样认为:传递的参数如果是“基本数据类型”,那就是“值传递”,如果是“引用类型”(即 对象),那就是“引用传递”。

但是昨天我突然觉得:好像。。。不一定!

诶,别急着怼我说:Nemo!你传递过对象没啊,把对象传过去,修改对象的属性值,属性值就是的的确确的修改了啊!

诶,你说的没错,确实是修改了,但是你也说了是修改对象的属性值,传过去的是对象地址,而你的实际操作并没有对你传入的地址进行修改,只是修改了对象地址下面的属性值。

如果只是修改对象地址下面的属性值的话,那么值传递和引用传递有差吗?

值传递:复制对象地址给函数,函数修改对象地址下面的属性值。
引用传递:引用对象地址给函数,函数修改对象地址下面的属性值。
这两者有差吗,无论是复制还是引用,传入的对象地址都没有改变,改变的只是对象地址下面的属性值。

类比:我们可以类比一下,你家的地址是“北京市海淀区清华园1号”

引用传递:你给我引用你的地址,我过去你的地址那,打开你家的门,偷你家电动车的电瓶。
值传递:你不给我你的地址,我从网上找到你的地址,复制一份,过去你的地址那,打开你家的门,偷你家电动车的电瓶。
你瞧瞧,这两者有差吗?无论是怎样拿到你家的地址,你家的电瓶我要定了啊,你家的电瓶都会被修改啊。

举例代码:

package temp;/** * @author Nemo * @date 2020/6/22 */public class ValueTransfer {    public static void main(String[] args) {        Home yourHome = new Home("你的家");        Nemo nemo = new Nemo();        nemo.steal(yourHome);        yourHome.show();    }}class Home {    public String name;    public boolean battery = true;    public boolean isBattery() {        return battery;    }    public void setBattery(boolean battery) {        this.battery = battery;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Home(String name) {        this.name = name;    }    public void show() {        if (this.isBattery()) {            System.out.println(name + "的电瓶还在哟~");        } else {            System.out.println(name + "的电瓶被偷了!");        }    }}class Nemo {    public void steal(Home home) {        //如果是引用传递的话,那么我把你的家整个都变为了别人的家,那么你的家对象上现在应该存放的是别人的家        //如果是值传递的话,那么我只是把你的家对象复制了一个新的,这个新的家是别人的家,我偷一个跟你家一模一样的别人家的电瓶,你家的电瓶应该不会变        home = new Home("别人的家");        home.battery = false;        home.show();    }}

在 Nemo 类的 steal 方法中,我们可以看到注释:

  1. 如果是引用传递,那么我把你的家整个都变为了别人的家,那么你的家对象上现在应该存放的是别人的家,并且你家(即 别人家)的电瓶也应该被我偷了。
  2. 如果是值传递,那么我只是把你的家对象参数复制了一个新的,这个新的家我设为了别人的家,我偷一个跟你家一模一样的别人家的电瓶,你家的电瓶应该不会变。

运行结果:

别人的家的电瓶被偷了!你的家的电瓶还在哟~

根据运行结果来看,很显然,是第二种情况,也就是值传递,我偷的是一个跟你家一模一样的别人家的电瓶,而你家的电瓶还在。

通过概念我们也能知道,这里是把实际参数的引用的地址复制了一份,传递给了形式参数。所以,上面的参数其实是值传递,把实参对象引用的地址当做值传递给了形式参数。

特殊情况String的举例说明

public static void main(String[] args) {   ParamTest pt = new ParamTest();   String name = "Nemo";   pt.pass(name);   System.out.println("print in main , name is " + name);}public void pass(String name) {   name = "NewNemo";   System.out.println("print in pass , name is " + name);}

上面的代码输出结果为

print in pass , name is NewNemoprint in main , name is Nemo

此时很多人就会被迷惑住了,心想,这不是引用数据类型吗,为什么方法内修改没有用???不是引用数据类型能修改成功吗??

为啥上面同样是传递对象,传递的String对象和Home对象的表现结果不一样呢?

其实,我们在pass方法中使用name = "NewNemo";试着去更改name的值,阴差阳错的直接改变了name的引用的地址。

因为这段代码,其实可以类比于会new一个String,再把引用交给name,即类比于:(虽然这是在字符串常量池新加了一个字符串,但是与new一个是差不多的意思,可以类比)

name = new String("NewNemo");

我们复制一份地址值,传地址值过去,结果方法把复制的地址值改变了,当然就没有改变原先的对象了!

而原来的那个"Nemo"字符串还是由实参持有着的,所以,并没有修改到实际参数的值。

结论

Java 中只有值传递

实验补充内容:

转载地址:http://sdtkz.baihongyu.com/

你可能感兴趣的文章
02、MySQL—数据库基本操作
查看>>
OpenJDK1.8.0 源码解析————HashMap的实现(一)
查看>>
MySQL-时区导致的时间前后端不一致
查看>>
2021-04-05阅读小笔记:局部性原理
查看>>
go语言简单介绍,增强了解
查看>>
python file文件操作--内置对象open
查看>>
架构师入门:搭建基本的Eureka架构(从项目里抽取)
查看>>
MongoDB 快速扫盲贴
查看>>
EXTJS4.2——10.Tab+Iframe
查看>>
one + two = 3
查看>>
sctf_2019_easy_heap
查看>>
PyQt5之音乐播放器
查看>>
Redis进阶实践之十八 使用管道模式提高Redis查询的速度
查看>>
SQL注入
查看>>
MPI Maelstrom POJ - 1502 ⭐⭐ 【Dijkstra裸题】
查看>>
Problem A - Sequence with Digits (数学推导)
查看>>
Problem 330A - Cakeminator (思维)
查看>>
LeetCode75 颜色分类 (三路快排C++实现与应用)
查看>>
C语言+easyX图形库的推箱子实现
查看>>
调试vs2019代码的流程
查看>>