Java參数传递方式
原文:http://blog.sina.com.cn/s/blog_59ca2c2a0100qhjx.html,我作了些改动并添加了一个实例,添加对照
本文通过内存模型的方式来讨论一下Java中的參数传递。
1、基本类型參数的传递方式
这里的内存模型涉及到两种类型的内存:栈内存(stack)和堆内存(heap)。基本类型作为參数传递时,传递的是这个值的拷贝。
不管你怎么改变这个拷贝,原值是不会改变的。
看下边的一段代码,然后结合内存模型来说明问题:
public class ParameterTransfer {
public static void main(String[] args) {
int num = 30;
System.out.println("调用add方法前num=" + num);
add(num);
System.out.println("调用add方法后num=" + num);
}
public static void add(int param) {
param = 100;
}
}
这段代码执行的结果例如以下:
调用add方法前num=30
调用add方法后num=30
程序执行的结果也说明这一点,不管你在add()方法中怎么改变參数param的值,原值num都不会改变。
下边通过内存模型来分析一下。
当运行了int num = 30;这句代码后,程序在栈内存中开辟了一块地址为AD8500的内存,里边放的值是30,内存模型例如以下图:
运行到add()方法时,程序在栈内存中又开辟了一块地址为AD8600的内存,将num的值30传递进来,此时这块内存里边放的值是30。运行param = 100;后,AD8600中的值变成了100。内存模型例如以下图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHd3bjIwMDk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
地址AD8600中用于存放param的值,和存放num的内存没有不论什么关系,不管你怎么改变param的值,实际改变的是地址为AD8600的内存中的值,而AD8500中的值并未改变,所以num的值也就没有改变。
2、对象类型參数的传递方式
1)先看下边的演示样例代码:
public class ParameterTransfer {
public static void main(String[] args) {
String[] array = new String[] {"huixin"};
System.out.println("调用reset方法前array中的第0个元素的值是:" + array[0]);
reset(array);
System.out.println("调用reset方法后array中的第0个元素的值是:" + array[0]);
}
public static void reset(String[] param) {
param[0] = "hello, world!";
}
}
执行的结果例如以下:
调用reset方法前array中的第0个元素的值是:huixin
调用reset方法后array中的第0个元素的值是:hello, world!
当对象作为參数传递时,传递的是对象的引用,也就是对象的地址。下边用内存模型图来说明。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHd3bjIwMDk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
当程序运行了String[] array = new String[] {"huixin"}后。程序在栈内存中开辟了一块地址编号为AD9500内存空间,用于存放array[0]的引用地址。里边放的值是堆内存中的一个地址。演示样例中的值为BE2500,能够理解为有一个指针指向了堆内存中的编号为BE2500的地址。堆内存中编号为BE2500的这个地址中存放的才是array[0]的值:huixin。
当程序进入reset方法后。将array的值,也就是对象的引用BE2500传了进来。这时,程序在栈内存中又开辟了一块编号为AD9600的内存空间,里边放的值是传递过来的值。即AD9600。
能够理解为栈内存中的编号为AD9600的内存中有一个指针,也指向了堆内存中编号为BE2500的内存地址,如图所看到的:
这样一来,栈内存AD9500和AD9600(即array[0]和param的值)都指向了编号为BE2500的堆内存。
在reset方法中将param的值改动为hello, world!后,内存模型例如以下图所看到的:
改变对象param的值实际上是改变param这个栈内存所指向的堆内存中的值。param这个对象在栈内存中的地址是AD9600,里边存放的值是BE2500。所以堆内存BE2500中的值就变成了hello,world!。程序放回main方法之后,堆内存BE2500中的值仍然为hello,world!,main方法中array[0]的值时,从栈内存中找到array[0]的值是BE2500。然后去堆内存中找编号为BE2500的内存,里边的值是hello,world!。
所以main方法中打印出来的值就变成了hello,world!
2)我们再来看个样例
class Dog{
int x,y;
int z=1;
Dog(int x,int y){
this.x=x;
this.y=y;
}
void move1(Dog d){
d.x=d.x+10;
d.y=d.y+10;
}
void move2(Dog d){
Dog d2=new Dog(100, 100);
d=d2;
}
}
public class UseDog {
public static void main(String[] args) {
// TODO Auto-generated method stub
Dog d1=new Dog(10,10);
d1.move2(d1);
System.out.print(d1.x+","+d1.y+":");
d1.move1(d1);
System.out.println(d1.x+","+d1.y+";");
}
}
输出结果为:10,10:20,20;
先解释10,10:当运行d1.move2(d1)时。d1(引用地址)传入move2中,栈内存开辟空间存入。之后新建对象d2,并将d2(引用地址)赋给d,那么d就指向了对象d2。因此并未改变d1所指向的堆内存值。
再解释20,20:当运行d1.move1(d1)时,d1(引用地址)传入move1中,栈内存开辟空间存入,即d指向了d1所指向的堆内存值。这时在move1中改变d所指向的对象的值,那么d1所指向的对象值也改变了。由于d和d1指向的是同一个对象。
3、总结
不管是基本类型作为參数传递,还是对象作为參数传递,实际上传递的都是值,仅仅是值的的形式不用而已。
第一个演示样例中用基本类型作为參数传递时。将栈内存中的值30传递到了add方法中。
第二个演示样例中用对象作为參数传递时,将栈内存中的值BE2500传递到了reset方法中。当用对象作为參数传递时。真正的值是放在堆内存中的。传递的是栈内存中的值。而栈内存中存放的是堆内存的地址,所以传递的就是堆内存的地址。这就是它们的差别。
补充一下,在Java中,String是一个引用类型,可是在作为參数传递的时候表现出来的却是基本类型的特性。即在方法中改变了String类型的变量的值后,不会影响方法外的String变量的值。关于这个问题。能够參考例如以下两个地址:
http://freej.blog.51cto.com/235241/168676
http://dryr.blog.163.com/blog/static/58211013200802393317600/
我认为是这两篇文章中提到的两个原因导致的。一个是String实际上操作的是char[],能够理解为String是char[]的包装类。二是给String变量又一次赋值后,实际上没有改变这个变量的值,而是又一次new了一个String对象。改变了新对象的值,所以原来的String变量的值并没有改变。
Java參数传递方式的更多相关文章
- java參数传递方式问题
java的參数传递方式到底是值传递还是引用传递,这一直是一个争论不休的问题,一直以来没有形成统一意见. 在这里,我也仅仅是说一说个人见解,不保证是对的,全当是抛砖引玉. 首先我的观点是java採用的是 ...
- java參数传递机制浅析
欢迎转载,转载请声明出处! ----------------------------------------- 前言: java语言中,參数的传递仅仅有一种机制.那就是值传递. 举例: 以下将通过几个 ...
- C语言函数參数传递原理
C语言中參数的传递方式一般存在两种方式:一种是通过栈的形式传递.还有一种是通过寄存器的方式传递的. 这次.我们仅仅是具体描写叙述一下第一种參数传递方式,第二种方式在这里不做具体介绍. 首先,我们看一下 ...
- ionic新手教程第七课-简要说明几种界面之间的參数传递及优缺点
截至2016年4月13日19点32分,我公布的ionic新手教程,已经公布6课了, 总訪问量将近6000,平均每节课能有1000的訪问量.当中訪客最多的是第三课有2700的訪客. watermark/ ...
- 參数传递(引用,指针,值传递)C++11
C++中,函数的參数传递方式有值传递.地址传递.传地址有指针和引用方式. 在函数參数中,传地址的理由有: 1.使被调函数能够改动主调函数中的数据对象: 2.传地址能够降低数据拷贝,提高程序运行速度. ...
- java课堂练习之可变參数与卫条件
/* 有人邀请A,B,C,D,E,F 6个人參加一项会议,这6个人有些奇怪.由于他们有非常多要求,已知: 1)A,B两人至少有1人參加会议: 2)A,E,F 3人中有2人參加会议. 3)B和C ...
- java 变长參数使用原则
1.java变长參数用...表示,如Print(String... args){ ... }; 2.假设一个调用既匹配一个固定參数方法.又匹配一个变长參数方法,则优先匹配固定參数的方法 3.假设一个 ...
- java -D參数简化增加多个jar【简化设置classpath】
1.-D<name>=<value> set a system property 设置系统属性. java命令引入jar时能够-cp參数,但时-cp不能用通配符(多个jar时 ...
- 【JAVA学习】“-Xmx1024m -Xms1024m -Xmn512m -Xss256k”——Java执行參数(转)
年轻代 年老代概念 http://jefferent.iteye.com/blog/1123677 JVM的堆的内存, 是通过以下面两个參数控制的 -Xms 最小堆的大小, 也就是当你的虚拟机启动后 ...
随机推荐
- 弹出框weeboxs 基本属性总结
使用前需包含以下jquery.js.bgiframe.js.weebox.js文件 boxid: null, //设定了此值只后,以后在打开同样boxid的弹窗时,前一个将被自 动关闭 boxclas ...
- 如何使用Gmail的别名功能?
Gmail真的是一个很好的邮箱,一直是我的最爱!它有一个很独特的功能-别名,用这个功能,我们就可以把一个 邮箱当成很多个邮箱来使用了! 1.Gmail 不提供传统别名 ,但是你可以收到发送到 your ...
- HDU 4293 Groups
模型挺好的dp题,其实这道题就是建一个模型然后就很容易想到递推过程了,我们可以把每个人的描述,存到数组a中,a[l][r]表示左边有l个,到第r个这个人所在一层停止...然后就可以写出转移状态方程了. ...
- HDU4452Running Rabbits(模拟)
HDU4452Running Rabbits(模拟) pid=4452" target="_blank" style="">题目链接 题目大意: ...
- Lucene.Net 2.3.1开发介绍 —— 二、分词(一)
原文:Lucene.Net 2.3.1开发介绍 -- 二.分词(一) Lucene.Net中,分词是核心库之一,当然,也可以将它独立出来.目前Lucene.Net的分词库很不完善,实际应用价值不高.唯 ...
- jquery的ajax提交form表单方式总结
方法一: function AddHandlingFeeToRefund() { var AjaxURL= "../OrderManagement/AjaxModifyOrderServic ...
- 一起talk C栗子吧(第十二回:C语言实例--单链表一)
各位看官们,大家好.从今天開始,我们讲大型章回体科技小说 :C栗子.也就是C语言实例.闲话休提, 言归正转. 让我们一起talk C栗子吧! 看官们,上一回中咱们没有说详细的样例,并且是说了样例中的文 ...
- 百度搜索结果页url参数详解
在百度首页输入任意关键词搜索之后,我们跳转到搜索结果页面,在浏览器的网址栏我们可以看到很长的一串url地址.那么,你真的了解这一串url的含义吗? s?:搜索 百度搜索结果页使用了重定向,因此我们看到 ...
- 执行Asp.net应用程序在Linux上的3种托管方式
执行Asp.net应用程序在Linux上的3种托管方式 想要执行Asp.net应用程序在Linux上.我们有3种选择: 1.使用Apache作为Webserver.使用mod_mono:http:// ...
- [Android学习笔记]Canvas的使用
Canvas文档 http://developer.android.com/training/index.html 在绘制view时候,重写onDraw(canvas)方法,可能需要在canvas上绘 ...