网站首页 > java教程 正文
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:1
main方法中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);
}
}
输出结果:
update方法中user:User(id=1)
main方法中user:User(id=1)
可以看出update方法修改user对象的属性,main方法中user对象也跟着变了。
这是不是说明Java支持引用传递呢?
并不是。这里在参数传递的过程中,只是把实参的地址拷贝了一份传递给形参,update方法中只修改了参数地址里面的内容,并没有对形参本身进行修改。
4. 总结
经过上述分析,Java参数传递中,不管传递的是基本数据类型还是引用类型,都是值传递。
当传递基本数据类型,比如原始类型(int、long、char等)、包装类型(Integer、Long、String等),实参和形参都是存储在不同的栈帧内,修改形参的栈帧数据,不会影响实参的数据。
当传参的引用类型,形参和实参指向同一个地址的时候,修改形参地址的内容,会影响到实参。当形参和实参指向不同的地址的时候,修改形参地址的内容,并不会影响到实参。
我是「一灯架构」,如果本文对你有帮助,欢迎各位小伙伴点赞、评论和关注,感谢各位老铁,我们下期见
猜你喜欢
- 2024-11-11 挨个举例子告诉你Java中的参数传递,我就不信你还不明白了
- 2024-11-11 Java值传递机制(java传值方式)
- 2024-11-11 Java面试-为什么 Java 只有值传递?
- 2024-11-11 Stack Overflow上188W+程序员都关注的问题
- 2024-11-11 为什么说Java不存在引用传递?(javax不存在)
- 2024-11-11 一份2021年的java面试题(java常见面试题)
- 2024-11-11 互联网大厂面试系列-为什么说在Java方法参数调用只有值传递呢?
- 2024-11-11 一文搞懂参数传递原理(参数传递的三种方式)
- 2024-11-11 Java程序员想年后跳槽,对JVM没有深入的理解,我劝你还是别跳了
- 2024-11-11 JAVA校招题基础知识点复习第二天(引用传递的本质是什么?)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)