[转帖]Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
http://www.itpub.net/2019/12/03/4567/
在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。实话实说吧,我就是其中之一。
来回顾一下提问者的问题:
我一直认为 Java 是按引用传递的,但是我看一些博客上说不是的。我就纳闷了,Java 到底是值传递还是引用传递?值传递和引用传递有什么区别呢?
如果你也曾被这个问题困扰过,或者正在被困扰,就请随我一起来梳理一下问题的答案。打怪进阶喽!
01、值传递和引用传递
什么是值传递,什么是引用传递?我们需要先把这两个定义搞清楚,才能搞清楚 Java 是按值传递还是按引用传递。
值传递(pass by value)是指在调用方法时将实参复制一份传递到方法中,这样当方法对形参进行修改时不会影响到实参。
引用传递(pass by reference)是指在调用方法时将实参的地址直接传递到方法中,那么在方法中对形参所进行的修改,将影响到实参。
上面是比较官方的定义,读起来不免生硬。在我看来,值传递和引用传递的关键区别有两点:
1)调用方法时有没有对实参进行复制。
2)方法内对形参的修改会不会影响到实参。
what?值传递和引用传递还没有搞清楚,又来两个新名词:实参和形参。别急,别急。
02、实参和形参
实参和形参理解起来比值传递和引用传递容易的多,前者就好像是一元一次方程,后者就像是一元二次方程。
形参:定义方法名和方法体的时候使用的参数,目的是用来接收调用该方法时传入的参数。
实参:在调用有参方法时传入的参数,方法名后面的括号中的参数通常被称为“实参”。
大家应该都写过“hello world”程序了,就像下面这样。
public class Cmower {
public static void main(String[] args) {
System.out.println("hello world");
}
}
其中 args 就相当于是形参,而字符串“hello world”就相当于是实参。如果觉得这个例子不容易理解,那再来看一个。
public class Cmower {
public static void main(String[] args) {
Cmower cmower = new Cmower();
cmower.sop("沉默王二");
}
public void sop(String name) {
System.out.println("hello " + name);
}
}
其中“沉默王二”为实参;有参方法 sop(String name) 中的 name 为形参。形参就好像实参与被调用方法之间的一个桥梁,否则调用者没法传递参数,被调用的方法无法接收参数。
03、基本类型是值传递的
Java 中的数据类型可以分为两种,一种是基本类型,一种是引用类型。我相信大家在看本篇文章之前,就能够达成这样一个共识:基本类型是值传递的。这一点毫无疑问。
public class Cmower {
public static void main(String[] args) {
Cmower cmower = new Cmower();
int age = 18;
cmower.sop(age);
System.out.println("main 中的 age " + age);
}
public void sop(int age) {
age = 28;
System.out.println("sop 中的 age " + age);
}
}
上面这段代码中,sop() 方法的实参 age 为 18,尽管 sop() 方法的形参被修改为 28,但并不会影响实参的值。这一点可以从输出结果中加以证明。
sop 中的 age 28
main 中的 age 18
具体的执行过程如下图所示。

04、引用类型是值传递吗?
大家之所以不确定 Java 是值传递的还是引用传递的,原因就出在这个引用类型上面。单从字面的意思上就容易搞混:引用类型不是引用传递难道还是值传递?
public class Cmower {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void main(String[] args) {
Cmower cmower = new Cmower();
cmower.setName("沉默王二");
cmower.sop(cmower);
System.out.println("main 中的 cmower " + cmower.getName());
}
public void sop(Cmower cmower) {
cmower.setName("沉默王三");
System.out.println("sop 中的 cmower " + cmower.getName());
}
}
在 main() 方法中,我们通过 new 关键字创建了一个对象 cmower,并将其 name 属性设置为“沉默王二”;然后将实参 cmower 传递给 sop() 方法,在 sop() 方法中将形参 cmower 的 name 属性修改为“沉默王三”。输出结果是什么样子呢?
sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
呀!实参 cmower 的属性 name 竟然不是“沉默王二”而是“沉默王三”了!看看,看看,Java 不是值传递吧?
别急别急。我们在 main 方法中追加几行代码。
Cmower cmower = new Cmower();
cmower.setName("沉默王二");
Cmower old = cmower;
cmower.sop(cmower);
System.out.println("main 中的 cmower " + cmower.getName());
System.out.println(old == cmower);
old == cmower 会是 true 还是 false 呢?闭上眼睛想一想。如果实在是想不出,抛一枚硬币吧,反正不是 true 就是 false。假如引用类型是引用传递的,根据引用传递的定义(形参的修改将会影响到实参),那么结果一定就是 false。
我们来看一下输出结果:
sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
true
true?开什么玩笑?
不好意思,没有开玩笑。Java 的确是值传递的。只不过,引用类型在调用有参方法的时候,传递的是对象的引用,并不是对象本身。而对象的引用在传递的过程中并没有发生改变,虽然对象本身发生了变化。可以通过下面这幅图感受一下。

这下理解了吧?
05、总结
来看下面这段代码。
int age = 18;
String name = "沉默王二";
age 是基本类型,所以值就直接保存在变量中;而 name 是引用类型,变量中保存的只是对象的内存地址,这种变量一般称之为对象的引用。
基本类型作为参数被传递时肯定是值传递;引用类型作为参数被传递时也是值传递,只不过“值”为对应的引用。
[转帖]Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?的更多相关文章
- Stack Overflow上59万浏览量的提问:为什么会发生ArrayIndexOutOfBoundsException?
在逛 Stack Overflow 的时候,发现了一些访问量像昆仑山一样高的问题,比如说这个:为什么会发生 ArrayIndexOutOfBoundsException?这样看似简单到不值得一问的问题 ...
- Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?
在逛 Stack Overflow 的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较 Java 的字符串?访问量足足有 370万+,这不得了啊!说明有很多很多的程序员被这个问题困 ...
- Stack Overflow 上人气最旺的 10 个 Java 问题
1. 为什么两个(1927年)时间相减得到一个奇怪的结果? (3623个赞) 如果执行下面的程序,程序解析两个间隔1秒的日期字符串并比较: public static void main(String ...
- 关于Stack Overflow上ASP.NET最大连接数限制提问的一个思考
原文地址:Why request queuing is high even when request executing is below its limit? We are using below ...
- Stack Overflow上关于Java Collections的几个常见问题
下面列出Stack Overflow上最常见的几个关于Java Collections的问题并给出答案. 1. 什么时候用LinkedList,什么时候用ArrayList? ArrayList是使用 ...
- 为什么开发者热衷在Stack Overflow上查阅API文档?
摘要:一项新研究跟踪了Android开发者的访问历史,发现开发者多达二分之一的文档是从Stack Overflow上获取到的,而Stack Overflow上的示例也多于官方指南,开发者通过搜索更多时 ...
- Stack Overflow 上排名前十的与API相关的问题
Stack Overflow是一个庞大的编程知识仓库,在Stack Overflow 上,数百万的提问被回答,并且这些回答都是高质量的.这就是为什么在Google搜索结果的排行榜上,Stack Ove ...
- JavaScript超越了Java,c,python等等成为Stack Overflow上最热门的
JavaScript超越了Java,c,python等等成为Stack Overflow上最热门的标签 在2015年6月至今,JavaScript超越了Java,c,python等等成为Stack O ...
- Stack Overflow 上 250W 浏览量的一个问题:你对象丢了
在逛 Stack Overflow 的时候,发现最火的问题竟然是:什么是 NullPointerException(java.lang.NullPointerException),它是由什么原因导致的 ...
随机推荐
- XSS Challenges 练习(1-10)
这几天对XSS Challenges平台进行了练习,网上也有一些相应的解答博客,但是写得都差不多,我觉得可以试一下从怎么做这种题的角度出发去思考问题. 第一题:http://xss-quiz.int2 ...
- space-cloud 支持多数据库多rest&& graphql web server
space-cloud 是一个开源的类似hasura 的graphql 引擎,但是space-cloud 同时支持rest api,而且支持多数据库 基于golang 编写,功能看着很强大 参考图 功 ...
- 【LG3783】[SDOI2017]天才黑客
[LG3783][SDOI2017]天才黑客 题面 洛谷 题解 首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点, 然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里 ...
- 牛客网 牛客练习赛4 A.Laptop-二维偏序+离散化+树状数组
A.Laptop 链接:https://ac.nowcoder.com/acm/contest/16/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其 ...
- nginx之系统参数优化
系统参数优化 默认的Linux内核参数考虑的是最通用场景,不符合用于支持高并发访问的Web服务器的定义,根据业务特点来进行调整,当Nginx作为静态web内容服务器.反向代理或者提供压缩服务器的服务器 ...
- 2019 第二届 科成安洵杯 官方WriteUp -17网安
长文预警:对应源码请加企鹅群获取:861677907 0x01 WEB 1.1 勇闯贪吃蛇大冒险 一进去就看出来是一道web页面JS的小游戏,提示说输入CDUESTC CTF即可闯关成功,但是存在着d ...
- Fluent瞬态结果导出为Ensight格式
参考: (1)<ANSYS Fluent User's Guide>的3.13.9. EnSight Case Gold Files (2)https://support.ceisoftw ...
- 《jmeter接口自动化与性能实战-飞天小子.pdf》
Jmeter作为开源测试工具,以其轻便,功能齐全的优点,正越来越受到企业的重视.作为纯java的工具,它的扩展性无比强大,既可以做功能测试,也可以做性能测试:既支持接口层面的测试,也支持webdriv ...
- Python开源项目Top30
原文地址:https://www.cnblogs.com/stoker/p/9101825.html No 1:Home-assistant (v0.6+) 基于Python 3的开源家庭自动化平台[ ...
- 阿里云环境安装K8S步骤
1. 安装docker yum install -y docker 2. 修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值 $ vim /et ...