JAVA语言中参数传递的深入剖析
2013-10-29陈兰芹
李 冉,陈兰芹
(荆楚理工学院 计算机工程学院,湖北 荆门448000)
Java语言中,参数传递机制对于初学者来说,一直是一个难点,也是一个重点。关于这方面的教材、论文和参考手册很多,但是说法不一,有的模糊带过。比如,有的认为Java的参数传递分两种情况,即值传递和引用传递;有的认为Java中所有的参数传递都是按值传递。其实这些说法都有一定的合理性,但是没有清晰地说明它的基本原理,容易让初学者陷入逻辑漩涡。本文参阅了各种说法,并结合了JDK的帮助文档,首先从Java的变量内存分配机制开始,全面深入地剖析Java语言中参数传递机制,并得出最合理的结论。
1 Java中变量的内存分配机制
Java的内存分配机制很复杂,这里只分析Java的变量内存分配规则,以助于理解Java的参数传递机制,而不考虑它在堆区、栈区还是静态数据区,也不考虑生命周期。
1.1 Java的数据类型
Java的数据类型分为两大类,分别是基本数据类型和引用数据类型[1]。基本数据类型,也称为简单数据类型,包括byte、char、short、int、long、float、double和boolean共8种;引用数据类型也称为复杂数据类型,包括接口、类和数组共3种。
1.2 变量及其内存分配规则
JVM根据变量的数据类型来分配内存空间,Java中不同大类型的变量内存分配规则不同。
1)对于基本数据类型
JVM对于基本数据类型的变量,只分配一定大小的内存单元,用于存储该变量的值。如果复制该变量,则是复制该内存单元的值,例如:
double x=7.3;//定义了双精度类型变量x,并赋初值为7.3
double y=x;//定义了双精度类型变量y,并copy了x的值
对应的内存单元示意图见图1。
图1 基本数据类型变量内存分配图
x变量的值复制给了y变量,此时,x、y是两个值相同的但是完全独立的两个内存单元。
2)对于引用数据类型
JVM对于引用数据类型的变量,也是分配一定大小的内存单元,用于存储该变量所指向的对象,该变量的值为对象的引用。如果复制该变量,实际上是复制了该变量内存单元的值,而不是复制它所指的对象的值,例如:
Point p1=new Point(23,34);//Point为Java中一个已有的类
Point p2=p1;//将p1的值复制给了p2变量对应的内存单元示意图见图2。
图2 引用数据类型变量内存分配图
p1变量的值复制给了p2变量,此时p1与p2存放的值是同一个对象的引用,即指向同一个对象,但是它们是两个完全独立的内存单元。
对于p1和它所指向的对象,本质上也是两个完全不同的内存单元。
2 Java参数传递机制
在Java语言中,参数传递是在程序运行过程中,实际参数将参数值传递给被调用的方法中相应的形式参数,然后实现对数据处理,或者完成特定的功能。实际参数是调用过程中,从主调方法传递给被调用方法的值,它可以是常量、变量或者表达式;形式参数是被调用方法用于接收并存储实际参数值的变量[2]。
Java语言中,参数传递的机制只有一个,即将实际参数的值复制一份赋值给形式参数,形式参数值的任何变化,不会影响到实参的值。实际参数可以是常量、变量或者表达式,变量又有很多种类型,但是都遵循这个机制。
2.1 实际参数为常量或者表达式的参数传递
Java语言中,常量和表达式都有值的属性,在参数传递中,将常量的值或者表达式计算的值复制一份赋值给形式参数。在方法内部,形式参数的值发生任何改变,不会影响到实际参数的值。实际上,常量和表达式的值不允许修改,也不可能修改。
2.2 实际参数为基本类型变量的参数传递
实际参数为基本类型变量时,参数传递过程中,将实参变量的值复制一份赋值给形式参数。实参变量和形参变量是两个独立的内存单元,形参变量的值发生任何变化,不会影响到实参变量的值,如下例程很好地验证这种传递逻辑关系。
运行结果如下:
在fun方法中,形参d的初始值,d=12.3
在fun方法中,形参d的初始值,d=15.3
在main方法中,实参f在fun方法执行之后的值,f=12.3
执行过程如图3所示。
图3 实参为简单类型变量的参数传递执行过程示意图
2.3 实际参数为引用类型变量的参数传递
实际参数为引用类型变量时,参数传递不是实参变量所指向的对象的值,而是实参变量本身的值,即所指对象的引用。传递的实现就是将实参变量所存储的引用的值复制一份赋值给形参变量,形参变量的内存单元也存储了该对象的引用值。但是形参变量与实参变量是两个独立的存储单元,形参变量内存单元值的变化不会影响到实参变量。如下例程很好地验证了这种逻辑关系。
运行结果如下:
图4 实参为引用类型变量的参数传递执行过程示意图
由图3和图4可以看出,引用类型实参到形参的参数传递,与简单类型实参到形参的传递方式一样,都是值的复制,只不过被复制的值的含义不同而已。
3 总结
在Java语言中,参数传递的机制本质上就是值的复制,即只是从实际参数到形式参数变量的值的复制。也可以说,在Java中,参数传递都是按值传递的,就像快递公司送包裹一样,不关心包裹的内容是什么。一些文章或者书籍中,将参数传递分为按值传递和按引用传递,是考虑了参数值的意义,这与Java参数传递的实现机制是没有关系的。初学者只要搞清楚了Java中变量类型分类和内存分配机制,就能灵活地使用参数传递机制。
[1]埃克尔.Java编程思想[M].陈昊鹏,译.4版.北京:机械工业出版社,2007.
[2]昊斯特曼.Java核心技术:卷I[M].叶乃文,邝劲筠,杜永萍,译.北京:机械工业出版社,2008.