关于Java对象作为参数传递是传值还是传引用的问题
前言
在Java中,当对象作为参数传递时,究竟传递的是对象的值,还是对象的引用,这是一个饱受争议的话题。若传的是值,那么函数接收的只是实参的一个副本,函数对形参的操作并不会对实参产生影响;若传的是引用,那么此时对形参的操作则会影响到实参。
首先我们来看一句代码:
Object obj = new Object();
这句话的意思是:创建一个Object对象,再创建一个名为obj的引用,让这个引用指向这个对象,如下图所示:
在有了上面的基础之后,我们便来看下面这组在网上很流行的例子:
基本数据类型作为参数传递:
例1:
public class test {
public static void main(String[] args) {
int i = 1;
System.out.println("before change, i = "+i);
change(i);
System.out.println("after change, i = "+i);
}
public static void change(int i){
i = 5;
}
}
这个例子不难理解,当基本数据类型(Boolean,byte,char,String,int,Long,float,double)作为参数传递时,传递的是实参值的副本,即传的是值,无论在函数中怎么操作这个副本,实参的值是不会被改变的。所以以上代码执行的结果是:
before change, i = 1
after change, i = 1
对象作为参数传递:
在下面的例2中,我们把StringBuffer对象作为参数传递到change函数。
例2:
public class test {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer.append("world !");
}
}
为了方便推理出结论,我们先直接看程序的运行结果:
before change, sb is Hello
after change, sb is Hello world !
从输出结果中我们可以发现,sb所指向的对象的值被改变了,那么是否我们可以推论出,在Java中,当对象作为参数传递时,传递的是该对象的引用呢?我们再来看下面这个例子:
public class test {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer = new StringBuffer("Hi ");
stringBuffer.append("world !");
}
}
如果上面的推论是正确的,即Java中对象作为参数传递,实际传递的是该对象的引用,那么在调用change函数之后,原对象的值应该是会改变的,变为“Hi world !”,但是,当我们运行程序后,结果却是如下所示:
before change, sb is Hello
after change, sb is Hello
原对象的值并没有被改变,这与上面的推论相矛盾!为什么在Java中,当对象作为参数传递时,有的时候实参被改变了,而有的时候实参并未被改变呢?下面让我们来分析一下其中的原因:
从文章的开头我们知道,当执行StringBuffer sb = new StringBuffer(“Hello “)时,我们创建了一个指向新建对象“new StringBuffer(“Hello “)”的引用“sb”,如下图所示:
在例2中,当我们调用change函数后,实际上,形参stringBuffer也指向了实参sb所指向的对象,即:
那么当我们执行stringBuffer.append(“world !”)后,便通过对象的引用“stringBuffer”修改了对象的值,使之变成了“Hello world !”,即:
但是,在例3中的change函数中,我们又新建了一个对象“new StringBuffer(“Hi “)”(这实际上在内存中开辟了一块在原对象地址之外的新区域),这让形参stringBuffer实际指向了这个新建的对象,并将新对象的值设置为“Hi world !”,例三中stringBuffer的值已经被改变为了Hi world,但是因为值没有被return返回赋值给sb对象,所以sb对象并没有被改变,所以输出的任然是hello,即:
那么我们就不难理解,为何在执行完change函数之后,实参的值仍为“Hello”了。
结论
综上所述,我们可以得出结论:在Java中,当对象作为参数传递时,实际上传递的是一份“引用的拷贝”。 (实际传递的是对象的引用)
转载自:https://blog.csdn.net/xiangwanpeng/article/details/52454479
关于Java对象作为参数传递是传值还是传引用的问题的更多相关文章
- Go 参数传递是传值还是传引用
什么是传值(值传递)? 传值的意思是:函数传递的总是原来这个东西的一个副本.一个副拷贝.比如我们传递一个 int 类型的参数,传递 的其实这个参数的一个副本:传递一个指针类型的参数,其实传递的是这个指 ...
- python函数的参数传递问题---传值还是传引用?
摘要:在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象.不可更改对象的传递属于传值,可更改对象属于传引用.想要在函数中传递 ...
- 难道同事:Java 方法调用到底是传值还是传引用
Java 方法调用中的参数是值传递还是引用传递呢?相信每个做开发的同学都碰到过传这个问题,不光是做 Java 的同学,用 C#.Python 开发的同学同样肯定遇到过这个问题,而且很有可能不止一次. ...
- 难住了同事:Java 方法调用到底是传值还是传引用
Java 方法调用中的参数是值传递还是引用传递呢?相信每个做开发的同学都碰到过传这个问题,不光是做 Java 的同学,用 C#.Python 开发的同学同样肯定遇到过这个问题,而且很有可能不止一次. ...
- JAVA方法传递参数:传值?传引用?
先来看下面这三段代码: //Example1: public class Example1 { static void check(int a) { a++; } public static void ...
- Java实参和形参与传值和传引用
实参和形参的定义: 形参出现函数定义中,在整个函数体内都可以使用,离开函数则不能使用. 实参出现在主函数中,进入被调函数后,实参变量也不能使用. 形参和实参的功能是做数据传送.发生函数调用时,主调函数 ...
- Java内存管理-Stackoverflow问答-Java是传值还是传引用?(十一)
勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 本文导图: 一.由一个提问引发的思考 在Stack Overflow 看到这样一个问题 ...
- 【转载】Java是传值还是传引用
1. 简单类型是按值传递的 Java 方法的参数是简单类型的时候,是按值传递的 (pass by value).这一点我们可以通过一个简单的例子来说明: /* 例 1 */ /** * @(#) Te ...
- Java经典问题:传值与传引用?
转自:http://developer.51cto.com/art/201104/254715.htm Java到底是传值还是传引用?相信很少有人能完全回答正确.通常的说法是:对于基本数据类型(整型. ...
随机推荐
- 处理http请求时,如何处理url的参数
1.@PathVariable 获取url中的数据 这种写法显得简洁 也可以把参数写在前面 @RequestParam 获取请求参数的值 适合传统的get提交参数的获取 给参数id设置一个默认值 不传 ...
- 阿里前端笔试总结--H5面试题
转载网址 https://blog.csdn.net/qq_20913021/article/details/51351801 1.有一个长度未知的数组a,如果它的长度为0就把数字1添加到数组里面,否 ...
- Java Programming Guidelines
This appendix contains suggestions to help guide you in performing low-level program design and in w ...
- Java Knowledge series 5
Interface from user, not from implementor.(DIP) Interface-Oriented Programming. Interface or Abstrac ...
- (C#) 线程之 AutoResetEvent, EventHandle.
AutoResetEvent 允许线程通过发信号互相通信.通常,此通信涉及线程需要独占访问的资源. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号.如果 AutoRese ...
- 【Android 界面效果47】RecyclerView详解
RecylerView作为 support-library发布出来,这对开发者来说绝对是个好消息.因为可以在更低的Android版本上使用这个新视图.下面我们看如何获取 RecylerView.首先打 ...
- memcached 的配置及 spymemcached 客户端简单使用
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.同时也可以用作不同系统之间的数据共享.应用比较广泛.下面介绍一下环境的memcached环境的搭建及简单实 ...
- Linux 下安装使用 oh-my-zsh
Ubuntu 下安装 oh-my-zsh 安装 zsh sudo apt install zsh 安装 git(如果你的系统没有自带的话) sudo apt install git 安装 oh-my- ...
- SourceTree Win10 安装过程及配置
SourceTree 是一款拥有可视化界面的项目版本控制软件,适用于git项目管理,同时它集成了 git flow 工作流程,对于不熟悉 git 命令的初学者来说,可以通过 SourceTree 快速 ...
- 使用ABAP(ADBC)和Java(JDBC)连接SAP HANA数据库
在表DBCON里维护一条记录,指向HANA数据库.con_ENV里填入HANA数据库的主机名和端口号.如vmXXXX:30015 DATA: ls_new TYPE DBCON. ls_new-con ...