java中传值方式的个人理解
前言
这几天在整理java基础知识方面的内容,对于值传递还不是特别理解,于是查阅了一些资料和网上相关博客,自己进行了归纳总结,最后将其整理成了一篇博客。
值传递
值传递是指在调用函数时将实际参数复制一份传递给形参,这样在函数中对形参的修改将不会影响到实际参数的值。
引用传递
引用传递是指在调用函数时将实际参数的地址直接传递到形参,那么在函数中对参数所进行的修改,将会影响到实际参数的值。
我们可以使用一段程序来验证Java中只有值传递
/**
* 验证java中只有值传递
* Dmego 2018-8-27
*/
class User{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class TestValue {
public static void change(User user2,int a2){
System.out.println("改变之前:"+user2.getName()+",a2="+a2);
user2.setName("李四"); //改变 user2 的 name 值
a2 = 10; //改变 a2 的值
System.out.println("改变之后:"+user2.getName()+",a2="+a2);
user2 = new User(); //将 user2 重新指向一个新对象
user2.setName("王五");
System.out.println("重新指向一个新对象后:"+user2.getName());
}
public static void main(String[] args){
User user1 = new User();
user1.setName("张三"); //初始化 user1 的 name 为张三
int a1 = 5; //初始化 a1 的值为 5
change(user1,a1); //调用方法验证传值方式
System.out.println("调用方法后:"+user1.getName()+",a1="+a1);
}
}
运行这段程序,输出结果为:
改变之前:张三,a2=5
改变之后:李四,a2=10
重新指向一个新对象后:王五
调用方法后:李四,a1=5
结果分析

下面我们以上图为辅助,来分析这段程序,首先我们定义了一个User类,然后在测试类中实例化了一个User对象,名为user1,并且为其赋值name = '张三',此时在内存中如图1所示,实例化一个对象相当于在堆中开辟了一块内存,内存地址为017,此时这个对象的引用为user1,内存地址为001,它保存了该对象在内存中的地址,也就是指向了该对象。接下了,我们调用方法change(),来尝试改变user1的name值以此验证java中的传值方式。
我们将user1作为实参传给change()方法,形参user2来接受这个实参,在这里就体现出了两种传参方式的不同。如果是按值传递,那么就像定义的那样,如图2所示,user2是user1的一份副本,也就是说在传递参数时,将user1(本身是一个对象的引用),复制了一份,名为user2,它同样也是一个对象的引用,并且user1和user2此时指向同一个对象。而如果是引用传递,也如同定义的那样,如图5所示,在传递参数时,是直接将user1传递给了形参,只是换了一个名字叫做user2,但是本质上user1和user2其实是同一个。它是一个对象的引用。
接着来分析输出的结果,不管是按值传递还是引用传递,第1行输出的结果一定都是张三,因为都是指向同一个对象。对于第2行输出,我们还是无法判断是哪种方式,因为都是改变同一个对象,值也会改变;关键在于第3行输出和第4行输出,此时,我们将user2重新指向了一个新的对象,并且为这个对象赋值name = '王五',如果是引用传递的方式,那么user1同样也会改变指向,指向新的这个对象,最后一行调用方法之后输出的结果将会和第3行一样是王五,但是事实输出的是李四,这表明user1和user2其实并不是同一个。真实的调用过程如 图2~图4所示,这样才会使得user2指向一个新的对象后,user1指向的对象并没有改变,还是原来那个对象。
对于基本类型的参数来说,a1的值最后没有改变,说明在执行方法时,a2是a1的一个副本。对于引用类型的参数来说,例如User对象,在调用方法时,实际上是将其引用user1作为实际参数,那么传递给形参的将是该引用的一份副本引用user2,虽然说这是两份引用(好比a1与a2的关系)。但是却指向同一个对象,所有的操作也都是对这同一个对象而言的。
最后举一个例子来形象的说明这一切,假如你有一把你房间的钥匙,并且在上面刻上了你的名字,这个过程好比给一个int类型的a1初始化值为5。你的朋友和你关系非常好,想要你房间的钥匙,此时你并没有直接把你的钥匙给他,而是复制了一把新的钥匙,这个钥匙也能开你的房间的门。而你的朋友在这把新钥匙上刻上了他的名字。这个过程就好比调用change()方法,把a1复制了一份赋值给a2,此时修改a2和a1没有任何关系,你朋友在新钥匙上刻他名字也不会影响你手上那把原始的钥匙。关键是这两把钥匙都能开你的房间,就好比user1和user2都指向同一个对象。此时你朋友用这把新钥匙打开了你的房间,将你房间电视机砸了。这个过程好比改名李四。这时你拿着你的钥匙打开你房间必然会看到这样的场景——电视机被砸了。就如同调用方法后user1变成了李四。在调用方法的过程中,最后user2重新指向了一个新的对象,这就好比你的朋友将你复制给他的钥匙再次进行了加工,此时不能开你房间的门,但是能开他自己的房间,他用这把钥匙开自己的房间然后把自己的电视砸了这并不会影响到你房间的电视,也就是说最后user1的名字并不会变成王五。这就是java中的值传递。当然了,如果是引用传递,那么这个例子中从头到尾将会只有一把钥匙,最后的结果也将会不同。
尾声
通过以上分析我们可以知道。Java中只有值传递这一种方式,只不过对于引用类型来说,传递的参数是对象的引用罢了。
java中传值方式的个人理解的更多相关文章
- java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)
java中传值及引伸深度克隆的思考 大家都知道java中没有指针.难道java真的没有指针吗?句柄是什么?变量地址在哪里?没有地址的话简直不可想象! java中内存的分配方式有两种,一种是在堆中分配, ...
- java中容器的学习与理解
以前一直对于java中容器的概念不理解,虽然学习过,但始终没有认真理解过,这几天老师提出了这样一个问题,你怎么理解java中的容器.瞬间就蒙了.于是各种搜资料学习了一下,下面是我学习后整理出来的的一些 ...
- java中GET方式提交和POST方式提交
java中GET方式提交的示例: /** * 获取关注列表; * @return */ @SuppressWarnings("unchecked") public static A ...
- java中多种方式读文件
转自:http://www.jb51.net/article/16396.htm java中多种方式读文件 一.多种方式读文件内容. 1.按字节读取文件内容 2.按字符读取文件内容 3.按行读取文件内 ...
- 浅谈对java中传参问题的理解
之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...
- JAVA中关于并发的一些理解
一,JAVA线程是如何实现的? 同步,涉及到多线程操作,那在JAVA中线程是如何实现的呢? 操作系统中讲到,线程的实现(线程模型)主要有三种方式: ①使用内核线程实现 ②使用用户线程实现 ③使用用户线 ...
- 关于Java中形参与实参的理解
今天阅读了一个写的非常棒的博文,通过此博文再次复习了Java中参数传递的知识(即值传递与引用传递的区别).参考网站http://www.cnblogs.com/binyue/p/3862276.htm ...
- java参数传值方式
java参数有值类型和引用类型两种.所以java参数的传值也就从这两个方面分析. 从内存模型来说参数传递更为直观一些,这里涉及到两种类型的内存:栈内存(stack)和堆内存(heap). 基本类 ...
- 关于java中Static关键字的加强理解
static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键字的用法和平常容易误解的地方,最后列 ...
随机推荐
- spring boot -thymeleaf-域对象操作
后台代码
- [EXP]Apache Superset < 0.23 - Remote Code Execution
# Exploit Title: Apache Superset < 0.23 - Remote Code Execution # Date: 2018-05-17 # Exploit Auth ...
- Java排序方法sort的使用详解(转)
一.对数组的排序: //对数组排序 public void arraySort(){ int[] arr = {1,4,6,333,8,2}; Arrays.sort(arr);//使用java.ut ...
- Android Bug分析系列:第三方平台安装app启动后,home键回到桌面后点击app启动时会再次启动入口类bug的原因剖析
前言 前些天,测试MM发现了一个比较奇怪的bug. 具体表现是: 1.将app包通过电脑QQ传送到手机QQ上面,点击安装,安装后选择打开app (此间的应用逻辑应该是要触发 [闪屏页Activity] ...
- Mysql 5.7 基于组复制(MySQL Group Replication) - 运维小结
之前介绍了Mysq主从同步的异步复制(默认模式).半同步复制.基于GTID复制.基于组提交和并行复制 (解决同步延迟),下面简单说下Mysql基于组复制(MySQL Group Replication ...
- JS实现图片懒加载插件
一.前言 我在前几篇博客的记录中,有说自己在做一个图片懒加载的功能,然后巴拉巴拉的遇到哪些问题,结果做完了也没对懒加载这个功能做一些记录,所以这篇文章主要针对我所实现的思路,以及代码做个记录,实现不佳 ...
- .Net Core缓存组件(Redis)源码解析
上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...
- [IOI2014] 假期
Description 有\(N(N\leq 10^5)\)个排列在一条线上的城市,每个城市有\(val_i\)个景点.每天你可以选择在当前城市\(i\)游览景点,或者前往城市\(i-1\)或城市\( ...
- angular 禁止缓存
angular 单页面开发,会存在和管理很多HTML和JS文件,缓存有时是个麻烦. 在开发和测试阶段,F12调出调试工具,禁止缓存F5刷新下就好了. 但是在客户那里缓存就体验效果不好,甚至认为有问题, ...
- windows 安装 keras
pip install keras 报错了,看报错信息是卡在scipy上了,查了一下 https://stackoverflow.com/questions/42240720/python-scipy ...