Java方法的参数传递
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
式,很纠结 Java 中“引用变量”的参数传递方式。在网上搜索了很多资料,都没有满意的 答案。一种答案简单粗暴:Java 中所有的参数只能“按值传递”;相比较而言,另一种说法 更容易接受:站在传递的是实参的复制值这个角度看,是“按值传递”;站在传递的是对象 的地址这个角度看,是“按地址传递”。但是,爱较真的百味峰爷还是不满意!因此,回味 了一下 C 语言和 Vb 中的参数传递方式。
void main() {
int b =5; /*初始化 b 值为 5*/ func(&b); /*调用函数 func,实参 b 的实参地址 FFF0 赋给形参 a*/ printf("%d",b); /*输出 b 的结果 */ getch(); } 运行结果为:
分析:
FFE0
5
int b =5; /*初始化 b 值为 5*/
在 C 语言和 Vb 中,函数参数传递分为“按值传递”和“按地址传递”。以 C 语言为例, 实参拥有两种可用来传递的“资源”:一是分配给实参的栈内存存储区地址,简称实参地址; 二是实参的存储区中所存放的值,简称实参值。假设某个实参 a 的实参地址为 FFE0,而该 存储区中存放的实参值为 200,则示意图如下:
void main() {
Int b =5; /*初始化 b 值为 5*/ func(b); /*调用函数 func,实参 b 值 5 的复制赋给形参 a*/ printf("%d",b); /*输出 b 的结果 */ getch(); } 运行结果为:
分析:
FFE0
5
Int b =5;
FFEA
5
func(b);
FFEA
FFE0
FFE0
5
func(&b); /*调用函数 func,实参 b 的实参地址 FFF0 赋给形参 a*/
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
FFEA
FFE0
FFE0
10
*a=10; /*让形参 a 指向的存储区存放值为 10 */
FFE0
10
执行完函数 func,形参被释放
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
Java 方法的参数传递(二)
——非“不可变对象”的引用变量作为参数
Java 对于引用类型的参数传递,与 8 种基本数据类型的参数传递不同。对于基本数据类 型的数据作为方法参数,是按值传递(passing by value),即将实参变量所指向的栈内存临 时存储区所存储数据(即实参变量的值)进行复制,然后传递给形参变量
actualParameter.temp); fun(actualParameter);//引用变量作为实参 System.out.println("fun() 调 用 后 实 参 actualParameter 的 值 : " +
actualParameter.temp); } public static void fun(Demo formalParameter) { //引用变量作为形参 formalParameter.temp = 888; }
FFE0
200
如果是“按值传递”,则实参 a 传送给形参的是其实参值的复制值,即 200;如果是“按 地址传递”,则实参 a 传送给形参的是其实参地址,即 FFE0。
★ C 语言中的“按值传递” /*定义函数 func */ func(int a) { a=10; /*让形参Байду номын сангаас a 等于 10 */ }
} 运行结果为:
三、分析
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
actualParameter
Temp=0
Demo actualParameter= new Demo();
actualParameter
Temp=80
actualParameter.temp =80;
actualParameter formalParameter
fun(actualParameter);
Temp=888
actualParameter
Temp=888
执行并退出 fun()方法后,formalParameter 所分配栈内存空间被释放。
从以上分析可以看出,实参 actualParameter 并未发生改变,改变的是其引用的对象 new Demo()。实参 actualParameter 是“以不变应万变”,以自身的不变来应付所引用对象 new Demo()的万变。
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
FFEA
10
a=10;
可见,在“按值传递”过程中,无论形参如何变化,对应的实参都能“毫发无损”,因 为形参得到的只是实参值的复制品。实参给了形参这个“复制品”后,就全身而退,让形参 自个儿去玩。
★ C 语言中的“按地址传递”(适用于指针变量) /*定义函数 func */ func(int *a) { *a=10; /*让形参 a 指向的存储区存放值为 10 */ }
那么变化的是谁呢?百味峰爷计划在《Java 方法的参数传递(三)》再行总结。
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
五、引用变量作为参数,参数传递究竟是“按值传递”,还是“按地址传递”? 百味峰爷在学习 c 和 Vb 的时候都遇到过“按值传递”和“按地址传递”的参数传递方
范例程序 ParameterPassingDemo02.java 的源代码: class Demo {
int temp; } public class ParameterPassingDemo02{
public static void main(String[] args) { Demo actualParameter= new Demo(); actualParameter.temp =80; System.out.println("fun() 调 用 前 实 参 actualParameter 的 值 : " +
首先,要弄明白两个不同的概念:对象,引用变量。对象是类的实例,存储位置位于“堆” (Heap)中。引用变量是存放对应“对象”存储区之首地址的变量,存储位置位于“栈” 中。因此,百味峰爷认为所谓以“对象”作为 Java 方法参数的说法不准确,更为准确的描 述应该是“引用变量作为 Java 方法参数”。 一、理论分析
可见,在“按地址传递”过程中,实参将自己的地址(实参地址)传递给形参,指针 形参就指向了实参的存储区域,从而实参和形参捆绑在一起,造成“一荣俱荣,一损俱损” 的局面。直到形参死掉后(形参所在函数执行结束),实参才能重获“独立”。
书归正传!在分析了 C 语言中的“按值传递”和“按地址传递”后,与 Java 中“引用 变量”的参数传递相比较,发现后者与前者的两种情况都有所不同。
综上所述,Java 中“引用变量”的参数传递即不是“按值传递”,也不是“按地址传递”。
Java 中“引用变量”的参数传递与 C 语言中的“按值传递”相比较:虽然实参传递给形 参的都是各自存储区中值的复制品,但是前者的值本质上是“地址”,当对应形参获得该“地 址”,就和实参指向同一个存储区。因此,Java 中“引用变量”的参数传递不属于传统意义 上的“按值传递”。
Java 中“引用变量”的参数传递与 C 语言中的“按地址传递”相比较:虽然传递的都是 “地址”,但是前者传递的是“第三者”(对象)的地址,后者传递的是“自己”(实参)的 地址。因此,前者形参、实参同时指向“第三者”(对象),是三角关系;而后者是形参指向 实参,是在二人世界中玩。故,因此,Java 中“引用变量”的参数传递也不属于传统意义上 的“按地址传递”。
四、对于“引用变量”作为方法参数,实参是否都能够“以不变应万变”? 答案:否! 接下来,百味峰爷试着做出如下的分析。编程过程中,有时候需要禁止某个“对象”被
改动内容。为此,Java 提供了 Immutable 类(譬如 String 类),该类的对象被称为“不可变 对象)”。根据定义,“不可变对象”是一种一旦构建好就不再变化的“对象”,在其生存期间 不可被改变内容。对于这类对象,实参仍然不会发生变化,但是它所引用的对象也没有变化, 因此谈不上“以不变应万变”,而是“不变”应“不变”。
Java 类中方法以“引用变量”作为形参,形参和实参在栈内存中都有各自独立的存储区。 参数传递时,将“引用变量”实参的存储区中所存储数据(实参值)进行复制,“复制值” 存入“引用变量”形参的存储区。因为“实参值”是特定“对象”在堆内存中存储的首地址, 所以参数传递操作使得形参和实参一样成为该“对象”的引用变量,即指向相同的堆内存区。 二、例证说明
void main() {
int b =5; /*初始化 b 值为 5*/ func(&b); /*调用函数 func,实参 b 的实参地址 FFF0 赋给形参 a*/ printf("%d",b); /*输出 b 的结果 */ getch(); } 运行结果为:
分析:
FFE0
5
int b =5; /*初始化 b 值为 5*/
在 C 语言和 Vb 中,函数参数传递分为“按值传递”和“按地址传递”。以 C 语言为例, 实参拥有两种可用来传递的“资源”:一是分配给实参的栈内存存储区地址,简称实参地址; 二是实参的存储区中所存放的值,简称实参值。假设某个实参 a 的实参地址为 FFE0,而该 存储区中存放的实参值为 200,则示意图如下:
void main() {
Int b =5; /*初始化 b 值为 5*/ func(b); /*调用函数 func,实参 b 值 5 的复制赋给形参 a*/ printf("%d",b); /*输出 b 的结果 */ getch(); } 运行结果为:
分析:
FFE0
5
Int b =5;
FFEA
5
func(b);
FFEA
FFE0
FFE0
5
func(&b); /*调用函数 func,实参 b 的实参地址 FFF0 赋给形参 a*/
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
FFEA
FFE0
FFE0
10
*a=10; /*让形参 a 指向的存储区存放值为 10 */
FFE0
10
执行完函数 func,形参被释放
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
Java 方法的参数传递(二)
——非“不可变对象”的引用变量作为参数
Java 对于引用类型的参数传递,与 8 种基本数据类型的参数传递不同。对于基本数据类 型的数据作为方法参数,是按值传递(passing by value),即将实参变量所指向的栈内存临 时存储区所存储数据(即实参变量的值)进行复制,然后传递给形参变量
actualParameter.temp); fun(actualParameter);//引用变量作为实参 System.out.println("fun() 调 用 后 实 参 actualParameter 的 值 : " +
actualParameter.temp); } public static void fun(Demo formalParameter) { //引用变量作为形参 formalParameter.temp = 888; }
FFE0
200
如果是“按值传递”,则实参 a 传送给形参的是其实参值的复制值,即 200;如果是“按 地址传递”,则实参 a 传送给形参的是其实参地址,即 FFE0。
★ C 语言中的“按值传递” /*定义函数 func */ func(int a) { a=10; /*让形参Байду номын сангаас a 等于 10 */ }
} 运行结果为:
三、分析
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
actualParameter
Temp=0
Demo actualParameter= new Demo();
actualParameter
Temp=80
actualParameter.temp =80;
actualParameter formalParameter
fun(actualParameter);
Temp=888
actualParameter
Temp=888
执行并退出 fun()方法后,formalParameter 所分配栈内存空间被释放。
从以上分析可以看出,实参 actualParameter 并未发生改变,改变的是其引用的对象 new Demo()。实参 actualParameter 是“以不变应万变”,以自身的不变来应付所引用对象 new Demo()的万变。
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
FFEA
10
a=10;
可见,在“按值传递”过程中,无论形参如何变化,对应的实参都能“毫发无损”,因 为形参得到的只是实参值的复制品。实参给了形参这个“复制品”后,就全身而退,让形参 自个儿去玩。
★ C 语言中的“按地址传递”(适用于指针变量) /*定义函数 func */ func(int *a) { *a=10; /*让形参 a 指向的存储区存放值为 10 */ }
那么变化的是谁呢?百味峰爷计划在《Java 方法的参数传递(三)》再行总结。
Java 方法的参数传递(二)——非“不可变对象”的引用变量作为参数
五、引用变量作为参数,参数传递究竟是“按值传递”,还是“按地址传递”? 百味峰爷在学习 c 和 Vb 的时候都遇到过“按值传递”和“按地址传递”的参数传递方
范例程序 ParameterPassingDemo02.java 的源代码: class Demo {
int temp; } public class ParameterPassingDemo02{
public static void main(String[] args) { Demo actualParameter= new Demo(); actualParameter.temp =80; System.out.println("fun() 调 用 前 实 参 actualParameter 的 值 : " +
首先,要弄明白两个不同的概念:对象,引用变量。对象是类的实例,存储位置位于“堆” (Heap)中。引用变量是存放对应“对象”存储区之首地址的变量,存储位置位于“栈” 中。因此,百味峰爷认为所谓以“对象”作为 Java 方法参数的说法不准确,更为准确的描 述应该是“引用变量作为 Java 方法参数”。 一、理论分析
可见,在“按地址传递”过程中,实参将自己的地址(实参地址)传递给形参,指针 形参就指向了实参的存储区域,从而实参和形参捆绑在一起,造成“一荣俱荣,一损俱损” 的局面。直到形参死掉后(形参所在函数执行结束),实参才能重获“独立”。
书归正传!在分析了 C 语言中的“按值传递”和“按地址传递”后,与 Java 中“引用 变量”的参数传递相比较,发现后者与前者的两种情况都有所不同。
综上所述,Java 中“引用变量”的参数传递即不是“按值传递”,也不是“按地址传递”。
Java 中“引用变量”的参数传递与 C 语言中的“按值传递”相比较:虽然实参传递给形 参的都是各自存储区中值的复制品,但是前者的值本质上是“地址”,当对应形参获得该“地 址”,就和实参指向同一个存储区。因此,Java 中“引用变量”的参数传递不属于传统意义 上的“按值传递”。
Java 中“引用变量”的参数传递与 C 语言中的“按地址传递”相比较:虽然传递的都是 “地址”,但是前者传递的是“第三者”(对象)的地址,后者传递的是“自己”(实参)的 地址。因此,前者形参、实参同时指向“第三者”(对象),是三角关系;而后者是形参指向 实参,是在二人世界中玩。故,因此,Java 中“引用变量”的参数传递也不属于传统意义上 的“按地址传递”。
四、对于“引用变量”作为方法参数,实参是否都能够“以不变应万变”? 答案:否! 接下来,百味峰爷试着做出如下的分析。编程过程中,有时候需要禁止某个“对象”被
改动内容。为此,Java 提供了 Immutable 类(譬如 String 类),该类的对象被称为“不可变 对象)”。根据定义,“不可变对象”是一种一旦构建好就不再变化的“对象”,在其生存期间 不可被改变内容。对于这类对象,实参仍然不会发生变化,但是它所引用的对象也没有变化, 因此谈不上“以不变应万变”,而是“不变”应“不变”。
Java 类中方法以“引用变量”作为形参,形参和实参在栈内存中都有各自独立的存储区。 参数传递时,将“引用变量”实参的存储区中所存储数据(实参值)进行复制,“复制值” 存入“引用变量”形参的存储区。因为“实参值”是特定“对象”在堆内存中存储的首地址, 所以参数传递操作使得形参和实参一样成为该“对象”的引用变量,即指向相同的堆内存区。 二、例证说明