最近跟Java中的值传递和引用传递杠上了,一度怀疑人生。查了很多资料,加上自己的理解,终于搞清楚了,什么是值传递和引用传递。也搞明白了,为什么大家都说Java只有值传递,没有引用传递。原来,我一直以来的认知都是错误的。。。

首先,需要了解一些概念性的东西。

形参与实参:

形参,是指在定义函数时使用的参数,目的是用于接收调用该函数时传入的参数。简单理解,就是所有函数(即方法)的参数都是形参。

实参,是指调用函数时,传递给函数的参数。

public static void main(String[] args) {int num = 3;printVal(num); //这里num是实参
}private static void printVal(int num) {num = 5; //这里num就是形参
}

值传递和引用传递

值传递:是指在调用函数时,将实际参数复制一份传递给函数,这样在函数中修改参数时,不会影响到实际参数。其实,就是在说值传递时,只会改变形参,不会改变实参。

引用传递:是指在调用函数时,将实际参数的地址传递给函数,这样在函数中对参数的修改,将影响到实际参数。

这里,需要特别强调的是,千万不要以为传递的参数是值就是值传递,传递的是引用就是引用传递。也不要以为传递的参数是基本数据类型就是值传递,传递的是对象就是引用传递。 这是大错特错的。以前的我,一直都是这样认为的,现在想来真是太天真了。判断是值传递还是引用传递的标准,和传递参数的类型是没有一毛钱关系的。

下面三种情况,基本上可以涵盖所有情况的参数类型。

当传递的参数是基本数据类型时:

public class TestNum {public static void main(String[] args) {int num = 3;System.out.println("修改前的num值:" num);changeValue(num);System.out.println("修改后的num值:" num);}private static void changeValue(int num) {num = 5;System.out.println("形参num值:" num);}
}

打印结果:

修改前的num值:3
形参num值:5
修改后的num值:3

可以发现,传递基本数据类型时,在函数中修改的仅仅是形参,对实参的值的没有影响。

需要明白一点,值传递不是简单的把实参传递给形参,而是,实参建立了一个副本,然后把副本传递给了形参。下面用图来说明一下参数传递的过程:

图中num是实参,然后创建了一个副本temp,把它传递个形参value,修改value值对实参num没有任何影响。

传递类型是引用类型时:

public class User {private int age;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public User(int age, String name) {this.age = age;this.name = name;}public User() {}@Overridepublic String toString() {return "User{"  "age="   age  ", name='"   name   '\''  '}';}
}
public class TestUser {public static void main(String[] args) {User user = new User(18, "zhangsan");System.out.println("修改对象前:" user);changeUser(user);System.out.println("修改对象后:" user);}private static void changeUser(User user) {user.setAge(20);user.setName("lisi");}
}

打印结果:

修改对象前:User{age=18, name='zhangsan'}
修改对象后:User{age=20, name='lisi'}

可以发现,传过去的user对象,属性值被改变了。由于,user对象存放在堆里边,其引用存放在栈里边,其参数传递图如下:

user是对象的引用,为实参,然后创建一个副本temp,把它传递给形参user1。但是,他们实际操作的都是堆内存中的同一个User对象。因此,对象内容的修改也会体现到实参user上。

传递类型是String类型(Integer等基本类型的包装类等同)

public class TestStr {public static void main(String[] args) {String str = new String("zhangsan");System.out.println("字符串修改前:" str);changeStr(str);System.out.println("字符串修改后:" str);}private static void changeStr(String str) {str = "lisi";}
}

打印结果:

字符串修改前:zhangsan
字符串修改后:zhangsan

咦,看到这是不是感觉有点困惑。按照第二种情况,传递参数是引用类型时,不是可以修改对象内容吗,String也是引用类型,为什么在这又不变了呢?

再次强调一下,传递参数是引用类型,并不代表就是引用传递,其实它还是值传递。此时的 lisi 和上边的 zhangsan 根本不是同一个对象。画图理解下:

图中,str是对象 zhangsan 的引用,为实参,然后创建了一个副本temp,把它传递给了形参str1。此时,创建了一个新的对象 lisi ,形参str1指向这个对象,但是原来的实参str还是指向zhangsan。因此,形参内容的修改并不会影响到实参内容。所以,两次打印结果都是zhangsan。

第三种情况和第二种情况虽然传递的都是引用类型变量,但是处理方式却不一样。第三种情况是创建了一个新的对象,然后把形参指向新对象,而第二种情况并没有创建新对象,操作的还是同一个对象。如果把上边changeUser方法稍作改变,你就会理解:

private static void changeUser(User user) {//添加一行代码,创建新的User对象user = new User();user.setAge(20);user.setName("lisi");
}

运行以上代码,你就会惊奇的发现,最终打印修改前和修改后的内容是一模一样的。
这种情况,就等同于第三种情况。因为,这里的形参和实参引用所指向的对象是不同的对象。因此,修改形参对象内容并不会影响实参内容。

修改对象前:User{age=18, name='zhangsan'}
修改对象后:User{age=18, name='zhangsan'}

总结:

从以上三个例子中,我们就能理解了,为什么Java中只有值传递,并没有引用传递。值传递,不论传递的参数类型是值类型还是引用类型,都会在调用栈上创建一个形参的副本。不同的是,对于值类型来说,复制的就是整个原始值的复制。而对于引用类型来说,由于在调用栈中只存储对象的引用,因此复制的只是这个引用,而不是原始对象。

最后,再次强调一下,传递参数是引用类型,或者说是对象时,并不代表它就是引用传递。引用传递不是用来形容参数的类型的,不要被“引用”这个词本身迷惑了。这就如同我们生活中说的地瓜不是瓜,而是红薯一样。

  1. 参数传递时,是拷贝实参的副本,然后传递给形参。(值传递)
  2. 在函数中,只有修改了实参所指向的对象内容,才会影响到实参。以上第三种情况修改的实际上只是形参所指向的对象,因此不会影响实参。

为什么大家都说Java中只有值传递?相关推荐

  1. 为什么说 Java 中只有值传递?

    对于初学者来说,要想把这个问题回答正确,是比较难的.在第二天整理答案的时候,我发现我竟然无法通过简单的语言把这个事情描述的很容易理解,遗憾的是,我也没有在网上找到哪篇文章可以把这个事情讲解的通俗易懂. ...

  2. java只有值传递_面试官:为什么 Java 中只有值传递?

    1.为什么 Java 中只有值传递? 首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语.按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(ca ...

  3. 为什么说Java中只有值传递(另一种角度)

    转载自 为什么说Java中只有值传递 对于初学者来说,要想把这个问题回答正确,是比较难的.在第二天整理答案的时候,我发现我竟然无法通过简单的语言把这个事情描述的很容易理解,遗憾的是,我也没有在网上找到 ...

  4. 一文彻底搞懂Java中的值传递和引用传递!

    关于Java中方法间的参数传递到底是怎样的.为什么很多人说Java只有值传递等问题,一直困惑着很多人,甚至我在面试的时候问过很多有丰富经验的开发者,他们也很难解释的很清楚. 我很久也写过一篇文章,我当 ...

  5. 为什么Java中只有值传递

    原文链接:https://www.cnblogs.com/wchxj/p/8729503.html 在开始深入讲解之前,有必要纠正一下大家以前的那些错误看法了.如果你有以下想法,那么你有必要好好阅读本 ...

  6. java只有值传递_为什么说java中只有值传递

    前言 这几天在整理java基础知识方面的内容,对于值传递还不是特别理解,于是查阅了一些资料和网上相关博客,自己进行了归纳总结,最后将其整理成了一篇博客. 值传递 值传递是指在调用函数时将实际参数复制一 ...

  7. java值传递和引用传递的例子,Java中的值传递和引用传递实例介绍

    代码如下: package Object.reference; public class People { private String name; private int age; public P ...

  8. 什么是值传递,什么是引用传递。为什么说Java中只有值传递。

    关于这个问题,在StackOverflow上也引发过广泛的讨论,看来很多程序员对于这个问题的理解都不尽相同,甚至很多人理解的是错误的.还有的人可能知道Java中的参数传递是值传递,但是说不出来为什么. ...

  9. 为什么说Java中只有值传递

    点击上方"程序员小灰",选择"置顶公众号" 有趣有内涵的文章第一时间送达! 本文转载自公众号 Hollis 对于初学者来说,要想把这个问题回答正确,是比较难的. ...

最新文章

  1. 曙光高性能集群系统管理员手册(链接)
  2. ERP平台的自动化测试技术实践
  3. Linux服务器集群系统(四)——LVS集群的负载调度
  4. ubuntu14.10 linux-header更新,Ubuntu 14.04 怎样升级到 Ubuntu 14.10
  5. Java程序员的日常—— IOUtils总结
  6. startService()和bindService()区别
  7. 关于max(X,Y),min(X,Y)
  8. Tomcat SSL Configuration
  9. @SuppressWarnings注解的详解
  10. MTP管理才能发展专家
  11. linux vi命令详解 修改几行,Linux系统——Vi命令讲解
  12. 自然语言处理(NLP)常用算法入门笔记
  13. pdf照片显示正常打印时被翻转_2020考研 | 准考证怎么打印你知道吗?
  14. Windows10卸载密钥导致win10未激活--解决
  15. 一个直肠癌患者的最后50天,转发自阮一峰博客
  16. 【科学常识】之《马太效应》
  17. 由于微信字体大小的设置导致rem布局的微信公众号页面发生错乱的问题总结
  18. 来到传统行业做程序员,从准备提桶跑路到引领技术风潮?背景
  19. 精美五子棋源码c语言,界面非常漂亮的五子棋源代码
  20. 西工大机考(公司理财)大作业网考

热门文章

  1. Create React App来搭建react项目
  2. 微服务系列(1)-who i am?
  3. TeamViewer经验介绍
  4. Nginx学习(一)——Nginx基础知识
  5. Word类似正则表达式的通配符查找替换
  6. 主流分布式文件系统对比
  7. egg.js学习笔记
  8. 韩媒盘点弹劾朴槿惠全过程 历时92天
  9. water Caustics
  10. 一步一步教你反向传播的例子