Java 值传递与“引用传递”
文章目录
- 1. Java 的值传递
- 2. Java 的"引用传递"
- 结语
1. Java 的值传递
通常认为Java 方法传参数都是值传递,关于值传递
的定义如下:
在方法被调用时,实参通过形参把它的
内容副本传入方法内部
,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响原始值的内容
简单的代码示例和打印结果如下
public static void main(String[] args) {int a = 10;changeTest(a);System.out.println("main:" + a);}public static void changeTest(int src) {System.out.println("changeTest before:" + src);src++;System.out.println("changeTest after:" + src);}
changeTest before:10
changeTest after:11
main:10
以上变量a定义为基本数据类型 int,我们知道它是存储在虚拟机栈内存中的
。虚拟机栈是Java方法执行的内存模型,栈中存放着栈帧,每个栈帧分别对应一个被调用的方法,方法的调用过程其实就是栈帧在虚拟机中入栈到出栈的过程。当程序中某个线程开始执行一个方法时就会相应的创建一个栈帧并且入栈(位于栈顶),在方法结束后,栈帧出栈
栈帧
: 用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素,每个栈帧中包括:
局部变量表
用来存储方法中的局部变量(非静态变量、函数形参)。当变量为基本数据类型时,直接存储值,当变量为引用类型时,存储的是指向具体对象的引用操作数栈
Java虚拟机的解释执行引擎被称为"基于栈的执行引擎",其中的栈就是指操作数栈指向运行时常量池的引用
存储程序执行时可能用到常量的引用方法返回地址
存储方法执行完成后的返回地址
了解以上情况后其实很好解释示例代码的结果:
首先调用
main()
方法,此时JVM为main()
方法往虚拟机栈中压入一个栈帧,即为当前栈帧,用来存放main()
中的局部变量表(包括参数)、操作栈、方法出口等信息,如a
是main()
方法中的局部变量,此时虚拟机栈如图所示
当执行到
changeTest()
方法时,JVM也为其往虚拟机栈中压入一个栈帧,用来存放changeTest()
中的局部变量等信息,因此方法参数src
是在changeTest()
方法所在的栈帧中,而其值是从a
复制得到的。此时虚拟机栈如图所示,在changeTest()
方法栈帧内部操作变量src
显然不会影响到main()
方法栈帧变量a
2. Java 的"引用传递"
引用传递
的定义如下:
引用也就是指向真实内容的地址值,在方法调用时,实参的地址通过方法调用被传递给相应的形参,在方法体内,形参和实参指向同一块内存地址,对形参的操作会影响到真实内容
上文解释了值传递
的过程,但是以下方法入参为引用类型数据的示例代码1
的打印结果与其明显不符。可以看到,在 main() 方法中,List
类型变量 a
没有做任何的元素操作,但是经过 changeTest()
方法添加了元素 99之后,main()
方法中的List
变量 a
也被加入了元素 99。内容发生了改变,这似乎完全符合“引用传递”的定义,对形参的操作,改变了实际对象的内容
public static void main(String[] args) {List<Integer> a = new ArrayList<>();changeTest(a);System.out.println("main:" + a);}public static void changeTest(List<Integer> src) {System.out.println("changeTest before:" + src);src.add(99);System.out.println("changeTest after:" + src);}
changeTest before:[]
changeTest after:[99]
main:[99]
但当我们使用几乎完全相同的示例代码2
,只是添加一行代码之后,结果又不一样了:main() 方法中的List
类型变量 a
的内容并没有被 changTest() 方法中的操作改变
public static void main(String[] args) {List<Integer> a = new ArrayList<>();changeTest(a);System.out.println("main:" + a);}public static void changeTest(List<Integer> src) {System.out.println("changeTest before:" + src);// 添加以下一行代码src = new ArrayList<>();src.add(99);System.out.println("changeTest after:" + src);}
changeTest before:[]
changeTest after:[99]
main:[]
要解释以上结果,首先我们要知道变量a定义为对象类型 List,它是存储在虚拟机堆内存中的
。JVM 中堆内存是一块线程共享的区域,对象和数组一般都分配在这一块内存中。这样,我们就可以很容易地解释:
- 程序执行到
main()
方法中的代码List<Integer> a = new ArrayList<>();
时,JVM会在堆内开辟一块内存,用来存储List
对象的所有内容,同时在main()
方法所在线程的栈帧中创建一个引用a
存储堆区中List
对象的内存地址,如图
- 对于
示例代码1
,执行到changeTest()
方法时,JVM也为其往虚拟机栈中压入一个栈帧,其中变量src
的值为main()
方法栈帧中变量a
的副本,故其指向了同一块内存区域
- 对于
示例代码2
,执行到changeTest()
方法时,在方法内部的代码src = new ArrayList<>();
重复了步骤 1 的过程,首先在堆中开辟内存,存储新建的对象,再将新对象内存地址赋值给变量src
。这样在对src
的操作其实是在操作新对象的内存地址,也就是改变新对象的内容
结语
通过以上分析,我们知道在Java中所有的参数传递,不管基本类型还是引用类型,都是值传递,只是在这个过程也分为两种情况:
1.如果是对基本数据类型的数据进行操作,
由于原始内容和副本都是存储实际值,并且是在不同的栈帧内
,因此形参的操作,不影响原始内容
2.如果是对引用类型的数据进行操作,分两种情况,一种是形参和实参保持指向同一个对象地址
,则形参的操作,会影响实参指向的对象的内容。一种是形参被改动指向新的对象地址(如重新赋值引用)
,则形参的操作,不会影响实参指向的对象的内容
Java 值传递与“引用传递”相关推荐
- Java中的值传递和引用传递
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答:是值传递.Java 编程语言只有值传递参数.当一个对象实例作为 ...
- Java值传递与引用传递
Java面试题: 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 答案基本上是:值传递 说明:得出这种结论的前提必须是&qu ...
- Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
来自:沉默王二 在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很 ...
- java 引用传递_详解java的值传递、地址传递、引用传递
详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前 ...
- Java中传参数--值传递和引用传递
** Java中传参数–值传递和引用传递 ** 在Java中,传参数分为值传递和引用传递. 在Java中的数据类型分为两大类:一类是引用类型,也叫类类型(除了String以外的所有复合数据类型,包括数 ...
- java的引用传递_Java的值传递和引用传递
首先来看一段代码: User类: 1 public classUser {2 privateString name;3 4 publicString getName() {5 returnname;6 ...
- java引用传递关键字_Java值传递和引用传递
Java值传递和引用传递 1 什么是Java值传递和引用传递 在Java中只有值传递,而没有引用调用.如果我们调用传递值的方法,则称为按值调用.在调用方法中完成的更改在调用方法时不受影响. 2 Jav ...
- java中的值传递和引用传递问题
值传递与引用传递 最近学基础的时候,老师讲了值传递和引用传递,这个问题一直不太明白,上网查了很多资料,按照自己的理解整理了一遍,发现之前不太明白的地方基本上想明白了,如有不正确的地方,欢迎指正,谢谢. ...
- 【Java基础】Java中的值传递、引用传递
Java中的值传递.引用传递 对于一个方法而言,参数是为该方法提供信息的,而不是想让该方法改变自己.--<Java编程思想> 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本 ...
- Java中值传递和引用传递原理以及区别
Java在参数传递时有两种:一种是按值传递,一种是按引用传递 值传递:值传递是指在调用方法时将实际参数复制一份传递到方法中,也就是说,在调用方法时,实际参数把他的值的副本传递给对应的形式参数.(注意这 ...
最新文章
- 汇编语言 在存储单元中显示字符串
- 利用opencv改变视频长宽
- MySQL为其他用户创建数据库_MYSQL添加新用户 MYSQL为用户创建数据库 MYSQL为新用户分配权限...
- 你对JVM三色标记的理解嘛?
- [python3] pyton socket 同步通信举例
- linux文本处理常用指令总结
- 凯利公式自动计算表_EXCEL——可自动计算的收支表,全函数计算,拿上就用!
- 用区块链保护共享数据?存储初创公司Gospel开始试水
- 使用statsvn统计svn中代码行
- python列表功能默写_python基础学习——列表list的功能
- python详细安装教程-python详细安装pip教程
- php 计算两点地理坐标的距离
- 动态规划实战14 leetcode-312. Burst Balloons
- 使用dsoframer演示ppt
- 2023CS保研经验分享(清深、上交、港科大、南大LAMDA、同济、东南Palm等)
- Android network基础知识 — IPv4和IPv6的区别
- excel如何去重统计户数_excel表格单一数据统计-Excel如何去重,然后统计数据?...
- 电脑网络没有问题,就是电脑连不上网的解决办法
- 一键获取网页中的全部图片并批量下载(国内淘宝天猫京东网站+国外商品页面)——亲测有效
- Matlab肤色分割
热门文章
- 近期关于新加坡你必须知道的5件事
- 修改tomcat默认端口号8080
- 智慧温室建造费用大揭秘
- 东师大计算机应用基础20秋在线作业1,东师计算机应用基础20秋在线作业1答案
- iBET Online Casino Malaysia ─ W88 Platform Introduction(iBET, iBET Online Casino, online casino, onl
- MATLAB创建脚本
- 著名数字藏品专家、数藏大会创始人高泽龙接受中国企业家杂志采访
- 要想焊好氩弧焊,这些工艺禁忌你要记牢
- 前端 苹果safari 兼容性问题
- Safari浏览器低版本时候,只发option-CorsFilter配置