Java调用方法参数究竟是传值还是传址?
之前阅读《Head First Java》的时候,记得里面有提到过,Java在调用方法,传递参数的时候,采用的是pass-by-copy的方法,传递一份内容的拷贝,即传值。
举一个最简单的例子:
public class Test {
public static void main(String[] args) {
int numberA = 1;
int numberB = 2;
swap(numberA, numberB);
System.out.println(numberA);
System.out.println(numberB);
} public static void swap(int a, int b) {
int c = a;
a = b;
b = c;
}
}
这里,swap(int a, int b)方法的目的是交换参数a, b 的值,不过这是不会实现的。
虽然在方法里面将变量a的值赋给了一个临时变量temp,再将变量b的值赋给了a,最后将temp的值赋给了b。这个时候,b中保存的是之前a中的值,a中保存的也是b中的值,起码在swap()方法里面,a和b的值已经交换过来了。
但是请注意,Java调用参数的方法是pass-by-copy,也就是说,虽然在swap()方法里,参数a和b(所谓的形参)获取了 numberA 和 numberB 的值(所谓的实参),但是获取值的方法是拷贝了实参的值赋给形参,并不是让形参直接指向实参在内存中的地址(所谓的指针)。
所以,这段代码输出的结果是:
1
2
点击查看
本例中用的是原始类型(Primitive Type)int,那么对于引用类型,是不是也是这样的呢?让我们来看下面这段代码:
import java.util.ArrayList;
import java.util.List; public class Test {
public static void main(String[] args) {
List<Integer> aList = new ArrayList<Integer>();
aList.add(1);
addToList(aList);
System.out.println(aList);
} public static void addToList(List<Integer> list) {
list.add(2);
}
}
这段代码里,我们首先新建了一个ArrayList aList,并向里面添加了一个数字“1”。然后我们尝试调用 addToList(List<Integer> list) 方法来向aList里面添加数字“2”。这样做是否会成功呢?
答案是,会成功的。输出结果为:
[1, 2]
点击查看
纳尼?刚刚不是还说,Java不是pass-by-copy传值的吗?
难道不是应该这样:list只是aList的一个复制品而已,不论在addToList()方法里面对list进行任何操作,最后都不会影响到aList()吗?
前一阵子我一直是这么想的,还和同事为了一个类似的问题争执了好久。他坚持说这里是传址的,可我清清楚楚地记得《Head First Java》里告诉我们,Java是pass-by-value的。。
但是现在来看,被调用的方法确确实实影响了主调方法参数的值。所以问题究竟出在哪里呢?
对于这个问题,我认真思考了一下,外加最近学习的OCA里也有提到这个,整理一下我自己的理解。
首先,Java确确实实是传值(pass-by-value)的,在上面的例子里,传过去的确确实实也是一个copy,但是不要忘了,引用型(Reference Type)变量里面存放的值究竟是什么。
我们这里的引用型变量aList被声明为 List<Integer>类型,也就是说,aList变量里面只可以接收对 List<Integer> 对象的引用。
这里所说的“引用”,其实也就是地址,也就是指针。
也就是说,当我们调用 addToList(List<Integer> list) 方法的时候,传给参数list的值,实际上是对相同对象的一个引用。用《Head First Java》里遥控器和家电的比喻来说的话,我们这里只有一台电视和一个遥控器。然后我们复制了一个一模一样的遥控器出来,两个遥控器拥有一模一样的功能,比如开关,选台,调音量等。。而我们的电视只有一台,所以,用另外一个遥控器,是确确实实可以对这一台电视进行操作的。
所以到这里就很清晰了,Java仍然是传值(pass-by-value)的语言,关键在于,你传的是什么样的一个值。
最后让我们来看看OCA上面关于这部分知识点的一个小练习,有几个小陷阱,自己好好分析:
public class ReturningValues {
public static void main(String[] args) {
int number = 1;
String letters = "abc";
number(number);
letters = letters(letters);
System.out.println(number + letters);
} public static int number(int number) {
number++;
return number;
} public static String letters(String letters){
letters += "d";
return letters;
}
}
先自己做一下,做完之后再看答案:
1abcd
点击查看
你做对了吗?如果做错了,最可能的原因是你没有注意到第5行只是调用了那个方法,而并没有获取到方法的返回值。以后自己写代码的时候一定要注意避免犯这个错误!
PS:为了把答案折叠起来,本来已经用Markdown写好了,硬是新开了一篇用TinyMCE编辑器改HTML,尽管完全没有人会来看。。
Java调用方法参数究竟是传值还是传址?的更多相关文章
- Java方法传递参数传值还是传址的问题
这几天重构项目代码遇到一个疑问:可不可以在方法A中定义一个boolean变量b为false,然后A调用方法C把b传递到C方法中经过一些列业务判断后修改为true,C执行结束后A方法中b的值还是原来的f ...
- 一段代码让你秒懂java方法究竟是传值还是传地址
先看看代码以及执行结果: 凝视写得非常清楚了.我就不多说了. 我说说我的结论.事实上在java中没有传值还是传址的概念,java仅仅有引用的概念.引用类似传址.只是是一个变量名中保存着对象的地址,地址 ...
- 五分钟学Java:可变参数究竟是怎么一回事?
在逛 programcreek 的时候,我发现了一些专注基础但不容忽视的主题.比如说:Java 的可变参数究竟是怎么一回事?像这类灵魂拷问的主题,非常值得深入地研究一下. 我以前很不重视基础,觉得不就 ...
- 新手容易混乱的String+和StringBuffer,以及Java的方法参数传递方式。
之前在交流群里和猿友们讨论string+和stringbuffer哪个速度快以及Java的方法参数传递的问题,引起了群里猿友的小讨论.最终LZ得出的结果是string+没有stringbuffer快, ...
- java方法中,传参是传值还是传址问题(对比C语言、C#和C++)
问题引出: 编写一个简单的交换值的小程序,如果我们只是简单地定义一个交换函数接收两个数,在函数内部定义一个中间变量完成交换.那么当我们把a,b两个实参传给这个函数时,往往得不到预期的结果.这是为什么呢 ...
- Java传值和传址
调用函数时,传的参数过去可能是传值,也可能是传址.如果是传值,函数内部的操作对参数的值没有影响:如果是传址,函数内部的操作是对参数指向的内存进行操作,会影响参数的值. Java到底是传值还是传址?用下 ...
- javascript的变量,传值和传址,参数之间关系
先把收获晾一下: 1.javascrip变量包含两种类型的值,一种为引用类型的值,一种是基本类型的值.引用类型包括:Array,Object,Function(可以这么理解,非基本类型的都是引用类型) ...
- JAVA传值与传址
要了解JAVA中的传值与传址问题,必要先要了解JVA中的栈内存和堆内存,>>>>点些查看<<<<昨天写的学习记录 栈:基本数据类型.数据的引用变量,这两 ...
- 工控随笔_18_西门子_WinCC的VBS脚本_07_变量作用域和传值、传址
在vbs脚本中也存在和其他编程语言一样的概念,那就是变量的作用域,变量的作用域决 定在什么范围内可以访问. 同样的在vbs脚本中对于变量也有一个生命周期, 变量的生命周期决定了变量的存续时间 这个主要 ...
随机推荐
- 【转】ORACLE AWR报告
转自:http://blog.csdn.net/liqfyiyi/article/details/8236864 About Oracle AWR Oracle AWR is a powerful m ...
- 毕设(一)C#的百度api调用
这个学期就要毕业了,选了一个无人机地面站软件设计的题目,这几天也开始着手做, 首先做了一个百度地图的调用,这里因为是上位机的开发,所有就不介绍Javascript的 调用方法,核心是用到一个类Http ...
- jquery模拟按下回车实现代码
简单地记下jquery实现回车事件,代码如下: 全局: 代码如下: $(function(){ document.onkeydown = function(e){ var ev = document. ...
- Rainyday.js – Rendering Raindrops with JavaScript
Posted · Category:GPL License,Tools 直击现场 The idea behind Rainyday.js is to create a JavaScript libra ...
- Topshelf结合Quartz.NET实现服务端定时调度任务
这周接受到一个新的需求:一天内分时间段定时轮询一个第三方WebAPI,并保存第三方WebAPI结果. 需求分析:分时段.定时开启.定时结束.轮询.主要工作集中在前三个上,轮询其实就是个Http请求,比 ...
- Qt 5.6.2 静态编译(VS2013 x86 target xp openssl icu webkit)
在去年4月份的时候,我写过一篇动态编译Qt5.6.0的文章,当时是为了解决webkit不能在winxp下面跑的问题,动态编译有一个缺点,就是发布的时候,要携带一大堆dll,使安装包的体积增大.而静态编 ...
- Spark之json数据处理
-- 默认情况下,SparkContext对象在spark-shell启动时用namesc初始化.使用以下命令创建SQLContext. val sqlcontext = new org.apache ...
- Spring Boot:整合MyBatis框架
综合概述 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单 ...
- 高性能高并发网站架构,教你搭建Redis5缓存集群
一.Redis集群介绍 Redis真的是一个优秀的技术,它是一种key-value形式的NoSQL内存数据库,由ANSI C编写,遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Val ...
- sentinel 滑动窗口统计机制
sentinel的滑动窗口统计机制就是根据当前时间,获取对应的时间窗口,并更新该时间窗口中的各项统计指标(pass/block/rt等),这些指标被用来进行后续判断,比如限流.降级等:随着时间的推移, ...