面试题:Java中为什么只有值传递?
作者:小牛呼噜噜 | https://xiaoniuhululu.com
计算机内功、JAVA底层、面试相关资料等更多精彩文章在公众号「小牛呼噜噜 」
经典的问题
Java 传参是值传递还是引用传递?这个问题很基础,但是许多人都有点懵
形参&实参
首先我们得了解关于参数的几个概念
形式参数:定义函数时使用的参数,用来接收函数传入参数,比如我们写个函数,函数中的参数为形式参数
public void test(String str) { //str为形式参数
System.out.println(str);
}
实际参数:我们调用函数时,函数名后面括号中的参数称为实际参数,必须有确定的值,如下面例子所示
public static void main(String[] args) {
A a = new A();
a.test("小 明"); //"小 明"则为实际参数
}
可以发现,当调用一个有参函数的时候,会把实际参数传递给形式参数。
这种传递的过程的参数一般有2种情况值传递和引用传递。
- 值传递:调用函数时将实际参数复制一份传递到函数中,函数内部对参数内部进行修改不会影响到实际参数,即
创建副本,不会影响原生对象
- 引用传递 :方法接收的是实际参数所引用的地址,不会创建副本,对形参的修改将影响到实参,即
不创建副本,会影响原生对象
我们还得知道:在Java中有2种数据类型,其中主要有基本数据类型和引用数据类型,除了8种基本数据类型以外都是引用数据类型,分别是byte,short,int,long,char,boolean,float,double
Java是值传递还是引用传递?
对于这个问题,我们先来看几个例子慢慢道来:
传参的类型:基本数据类型
public class TestBasic {
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
change(num1, num2);
System.out.println("==============");
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void change(int param1, int param2) {
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
param1 = 333;
param2 = 444;
System.out.println("after change....");
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
}
结果:
param1 = 10
param2 = 20
after change....
param1 = 333param2 = 444
==============
num1 = 10
num2 = 20
我们可以发现,change()方法内对变量重新赋值,并未改变变量num1和num2的值,改变的只是change()方法内的num1和num2的副本。
我们需要知道,基本数据类型在内存中只有一块存储空间,分配在栈stack中。
Java传参的类型如果是基本数据类型,是值传递。
传参的类型:引用数据类型
public class TestQuote {
public static void main(String[] args) {
String str = "小明";
StringBuilder str2 = new StringBuilder("今天天气好");
change(str,str2);
System.out.println("==============");
System.out.println("str = " + str);
System.out.println("str2 = " + str2);
}
public static void change(String param1,StringBuilder param2) {
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
param1= "小张";
param2.append(",我们去钓鱼");
System.out.println("after change....");
System.out.println("param1 = " + param1);
System.out.println("param2 = " + param2);
}
}
结果:
param1 = 小明
param2 = 今天天气好
after change....
param1 = 小张param2 = 今天天气好,我们去钓鱼
str = 小明
str2 = 今天天气好,我们去钓鱼
我们发现str变量没有改变,但是str2变量却改变了,大家是不是迷惑了:Java传参的类型如果是引用数据类型,是值传递还是引用传递?
其实大家被一堆术语给忽悠了,笔者画了2张图,帮助大家理解:
before change():
after change():
在Java中,除了基本数据类型以外,其他的都是引用类型,引用类型在内存中有两块存储空间(一块在栈stack中,一块在堆heap中)
。
如果参数是引用类型,传递的就是实参所引用的对象在栈中地址值的拷贝,这里创建的副本是 地址的拷贝
。那就有人说了,可是它值变了呀,这明明就是"引用传递"嘛?
我们可以换个角度理解,如果我们把栈地址
当成值
,会创建栈地址副本(复制栈帧),栈地址最终并没有改变,改变的是堆内存中的值。这就好比栈地址是钥匙,我们copy了一把,它能打开保险箱。我们关心的是钥匙有没有花纹这种变化,至于打开保险箱后的钱多钱少,我们并不需要关心。
虽然调用完函数后,str2变量值(堆中的数据)改变了,但是参数是引用类型,传递的实参是 栈中地址值,这是我们关心的,拷贝的是栈中地址值,最终栈中地址值并没有改变。所以是符合值传递的定义创建副本,不会影响原生对象
。
可能又有人问了,那str变量值为啥没有改变呢?其实这完全是由于String类
的特殊,我们知道它是不可变的final,这个时候在函数中 param1= "小张";其实会隐式创建一个新的String对象,同时堆内存中会开辟一个新的内存空间,param1指向了这个新开辟的内存空间。原地址str指向的堆内存空间中数据没有任何改变。
尾语
Java中只有值传递,始终是传值的,我们要牢记,这个是官方明确说的。我们还应该清楚,其中的缘由。
参数是基本数据类型,复制的是具体值;如果参数是引用类型,把地址当成值,复制的是地址;还有String类是一个非常特殊的类,她是不可变的。
参考资料:
《深入理解Java虚拟机:JVM高级特性与最佳实践》
https://www.cnblogs.com/ITnoteforlsy/p/12266409.html
本篇文章到这里就结束啦,很感谢你能看到最后,如果觉得文章对你有帮助,别忘记关注我!
面试题:Java中为什么只有值传递?的更多相关文章
- Java中到底是值传递还是引用传递?
Java中到底是值传递还是引用传递? 我们先回顾一下基本概念 实参和形参 参数在编程语言中是执行程序需要的数据,这个数据一般保存在变量中.在Java中定义一个方法时,可以定义一些参数, 举个例子: p ...
- Java中真的只有值传递么?
Java中真的只有值传递么? (本文非引战或diss,只是说出自己的理解,欢迎摆正心态观看或探讨) 回顾值传递和引用传递 关于Java是值传递还是引用传递,网上有不一样的说法. 1.基本类型或基本类型 ...
- 2013年6月19日星期三java中函数地址值传递
今天代码审核时确认了一个问题,理解了java中string和stringbuffer赋值问题,看到一个帖子很好,摘录如下: 理解这两个例子需要分清实参和形参的区别,引用和对象的区别 第一个例子的内部执 ...
- java中的参数传递——值传递、引用传递
参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递. 在 Java 应用程序中永远不会传递对象,而只传递对象引用.因此是按引用传递对象.Java 应用程序按引用 ...
- java中函数是值传递还是引用传递?
相信有些同学跟我一样,曾经对这个问题很疑惑.在网上也看了一些别人说的观点,评论不一.有说有值传递和引用传递两种,也有说只有值传递的,这里只说下个人见解 先看一个例子 public class Test ...
- Java 参数传递都是值传递
Java 参数传递都是值传递,验证代码如下 public class ParamTransferTest { public static void swap(int a, int b) { int t ...
- java 传参方式--值传递还是引用传递
java 传参方式--值传递还是引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递.写它是为了揭穿普遍存在的一种神话,即认为 Java 应用程序按引用 ...
- Java的参数传递是值传递还是引用传递?
一.前言 首先先说结论,Java中方法参数传递方式是按值传递.如果参数是基本类型,传递的是基本类型的字面量值的拷贝.如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝. 接下来深入了解一 ...
- Java面向对象-方法的值传递和引用传递
Java面向对象-方法的值传递和引用传递 0 发布时间:『 2016-08-21 14:21』 博客类别:Java核心基础 阅读(197) 评论(0) Java面向对象-方法的值传递和引用传递 方 ...
随机推荐
- 论文解读《Deep Attention-guided Graph Clustering with Dual Self-supervision》
论文信息 论文标题:Deep Attention-guided Graph Clustering with Dual Self-supervision论文作者:Zhihao Peng, Hui Liu ...
- Java实现飞机大战游戏
飞机大战详细文档 文末有源代码,以及本游戏使用的所有素材,将plane2文件复制在src文件下可以直接运行. 实现效果: 结构设计 角色设计 飞行对象类 FlyObject 战机类 我的飞机 MyPl ...
- Tarjan入门
Tarjan系列!我愿称Tarjan为爆搜之王! 1.Tarjan求LCA 利用并查集在一遍DFS中可以完成所所有询问.是一种离线算法. 遍历到一个点时,我们先将并查集初始化,再遍历完一个子树之后,将 ...
- 史上最全Spring Cloud Alibaba--Nacos教程(涵盖负载均衡、配置管理、多环境切换、配置共享/刷新、灰度、集群)
能够实现Nacos安装 基于Nacos能实现应用负载均衡 能基于Nacos实现配置管理 配置管理 负载均衡 多环境切换 配置共享 配置刷新 灰度发布 掌握Nacos集群部署 1 Nacos安装 Nac ...
- conda命令的使用,环境安装,创建环境以Anaconda为例
Anaconda用命令conda创建环境: 安装Anaconda后,用Conda –version查看conda的版本号: Conda create -n name python = x.xx Con ...
- VTK 在WINDOWS上的安装使用
参考:http://www.vtk.org/Wiki/VTK/Building/Windows#Step_5_-_Open_the_Visual_Studio_project
- 使用PowerShell压缩和解压ZIP包
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月13日. 解压ZIP包 使用PowerShell的Expand-Archive命令.PowerShell官方文档地址. 命令格式: ...
- 部署ASP.NET Core最简单的办法,使用IIS部署ASP.NET Core应用
本文迁移自Panda666原博客,原发布时间:2021年3月28日.写原文的时候.NET的最新版本是5.0,现在7的preview出来了,时间真快啊.抽空再写个在Windows Server Core ...
- springboot available: expected at least 1 bean which qualifies as autowire candidate奇葩问题
Exception encountered during context initialization - cancelling refresh attempt: org.springframewor ...
- JS:函数
Function:函数 1. 定义一个函数:function functionname(argument) { 代码块 return }: 调用此函数:fn() 2.函数是定义了一种方法,只有被调用才 ...