Java到底是值传递还是引用传递?
这虽然是一个老生常谈的问题,但是对于没有深入研究过这块 , 或者Java基础不牢的同学,还是很难回答得让人满意 。
可能很多同学能够很轻松的背出JVM、分布式事务、高并发、秒杀系统、领域模型等高难度问题,但是对于Java基础问题不屑一顾 。这种抓大放小的初衷是对的 , 要是碰到深究基础细节的面试官,就抓瞎了 。
今天一灯带你一块深入剖析Java传递的底层原理,看完这篇文章再去面试 , 面试官肯定要竖起大拇哥夸你:
“小伙子 , 你是懂Java传递的!”
1. 什么是形参和实参形参: 就是形式参数,用于定义方法的时候使用的参数,是用来接收调用者传递的参数的 。
实参: 就是实际参数,用于调用时传递给方法的参数 。实参在传递给别的方法之前是要被预先赋值的 。
/** * @author 一灯架构 * @apiNote Java传递示例 **/public class Demo {public static void main(String[] args) {String name = "一灯架构"; // 这里的name就是实际参数update(name);System.out.println(name);}// 这里方法参数列表中name就是形式参数private static void update(String name) {// doSomething}}
在Java方法调用的过程中,就是把实参传递给形参,形参的作用域在方法内部 。
2. 什么是值传递和引用传递值传递: 是指在调用方法时,将实际参数拷贝一份传递给方法,这样在方法中修改形式参数时,不会影响到实际参数 。
引用传递: 也叫地址传递,是指在调用方法时,将实际参数的地址传递给方法,这样在方法中对形式参数的修改,将影响到实际参数 。
也就是说值传递,传递的是副本 。引用传递,传递的是实际内存地址 。这是两者的本质区别,下面会用到 。
3. 测试验证3.1 基本数据类型验证先用基本数据类型验证一下:
/** * @author 一灯架构 * @apiNote Java传递示例 **/public class Demo {public static void main(String[] args) {int count = 0;update(count);System.out.println("main方法中count:" + count);}private static void update(int count) {count++;System.out.println("update方法中count:" + count);}}
输出结果:
update方法中count:1main方法中count:0
可以看到虽然update方法修改了形参count的值,但是main方法中实参count的值并没有变,但是为什么没有变?我们深究一下底层原理 。
我们都知道Java基本数据类型是存储在虚拟机栈内存中,栈中存放着栈帧 , 方法调用的过程,就是栈帧在栈中入栈、出栈的过程 。
当执行main方法的时候,就往虚拟机栈中压入一个栈?。?栈帧中存储的局部变量信息是count=0 。

文章插图
当执行update方法的时候,再往虚拟机栈中压入一个栈帧 , 栈帧中存储的局部变量信息是count=0 。

文章插图
修改update栈帧中数据,显然不会影响到main方法栈帧的数据 。
3.2 引用类型验证再用引用类型数据验证一下:
/** * @author 一灯架构 * @apiNote Java传递示例 **/public class Demo {public static void main(String[] args) {User user = new User();user.setId(0);update(user);System.out.println("main方法中user:" + user);}private static void update(User user) {user = new User();user.setId(1);System.out.println("update方法中user:" + user);}}
输出结果:update方法中user:User(id=1)main方法中user:User(id=0)
由代码得知,update方法中重新初始化了user对象,并重新赋值,并不影响main方法中实参数据 。当执行main方法时,会在堆内存中开辟一块内存,在栈内存中压入一个栈?。?栈帧中存储一个引用 , 指向堆内存中的地址 。

文章插图
当调用update方法时,会把main方法的栈帧拷贝一份,再压入栈内存中,指向同一个堆内存地址 。

文章插图
当执行update方法,重新初始化user对象,并重新赋值的时候 。会在堆内存中再开辟一块内存,再把栈内存中update栈帧指向新的堆内存地址,并修改新的堆内存中的数据 。

文章插图
从这里可以看出是值传递,修改了形参里面数据 , 实参并没有跟着变化 。
3.3 同一地址的引用类型验证
/** * @author 一灯架构 * @apiNote Java传递示例 **/public class Demo {public static void main(String[] args) {User user = new User();user.setId(0);update(user);System.out.println("main方法中user:" + user);}private static void update(User user) {user.setId(1);System.out.println("update方法中user:" + user);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Java集合精选常见面试题
- Redis系列9:Geo 类型赋能亿级地图位置计算
- RTX40系列价格_RTX40系列显卡价格
- [Android开发学iOS系列] Auto Layout
- CH58X服务修改
- 0 二 C# 语法分析器LR 语法分析
- iphone13系列价格_iphone13全系列价格
- 百雀羚帧颜霜孕妇可以用吗_百雀羚帧颜系列孕妇可以用吗
- vivoT1值得买吗_vivoT1值不值得买
- 六 Selenium4+Python3系列 - Selenium的三种等待,强制等待、隐式等待、显式等待