Java的参数传递方式
在编程中,往方法中传递参数的方法往往有两种,一种是值传递,一种是引用传递,而在java中,所有的参数传递全部都是值传递。但是实际使用中往往会出现一些类似引用传递的方式,下面我将一一举例说明。
首先,java中的所有的对象都是通过“引用”操作的。
java中有五个不同的地方可以储存对象。
1)寄存器:这是最快的储存区域,但是这个区域并不能由用户直接控制,用户也感觉不到寄存器的存在。
2)堆栈:位于通用RAM中,通过堆栈指针可以获得直接支持。Java的对象引用及储存在堆栈之中,但是java对象并不储存在堆栈中。
3)堆:一种通用的内存池,也存在于RAM中,用于存放所有的java对象,通过new关键字创建的对象都会存在于堆中。
4)常量储存:常量值通常直接存在于程序代码内部,并存放在ROM(只读存储器)中。
5)非RAM储存:存活于程序之外的数据。
1.传递基本类型数据。
java中的基本类型数据即 int,char这一类。测试代码如下:
1 package com.csust.wk; 2 public class FunctionTest1 { 3 public static void change(int b){ 4 b = 10; 5 } 6 7 public static void main(String[] args) { 8 int i = 5; 9 System.out.println(i); 10 change(i); 11 System.out.println(i); 12 } 13 }
程序输出:
5
5
由结果可见,传入change()方法中的变量并没有被改变。
结果分析:
在基本类型int创建的过程中,如int a = 5; java首先会在堆栈中(所有基本类型的创建和保存都是在堆栈中进行的操作)查询有没有5这个值,如果没有则会在堆栈中开辟一个新的内存空间同时将5置入该空间。然后a这个引用就指向了5所在的内存空间。
这么看的话,将a传入change()方法之中后,形参b指向了main函数中的实参a的地址(此处也是值传递,因为java 复制了一份实参a 的地址然后将其赋给b),对b进行b=10的操作时,java则按照以上的规则进行操作,由于a,b并不是同一个引用,所以当b的引用地址改变成10以后,a所指向的依旧是5所在的地址,这样就可以得到以上的输出结果了。另附基础对象
public static void main(String[] args) { /* * 基础对象测试代码2 */ int a = 5; int b = a; b = 10; System.out.println(a); System.out.println(b); }
2.数组数据传递
测试代码:
package com.csust.wk; public class FunctionTest1 { public static void change(int[] arg){ arg[0] = 10; } public static void main(String[] args) { int[] arg = {1,2,3,4,5,6}; System.out.println(arg[0]); change(arg); System.out.println(arg[0]); } }
程序输出:
1
10
结果可见:传入的arg数组中的值被改变了,arg[0]由1变成了10。
结果分析:
数组实际上结构是保存了一系列的引用,arg[0]是一个指向数组中第一个int储存空间的引用。而arg则是指向了该数组的引用。
当arg被传入change()方法时,复制了一个arg的引用,但是该arg也是只想实参arg的地址的,所以对arg[0]进行操作时实际上也是对元数组进行了赋值操作,当回到main函数时,调用的依旧是change()中操作的地址,所以第二次输出会变成 10 。
3.对象传递
测试代码:
package com.csust.wk; class TestClass { int a; } public class FunctionTest1 { public static void change(TestClass c){ c.a = 10; } public static void main(String[] args) { TestClass cla = new TestClass(); cla.a = 5; System.out.println(cla.a); change(cla); System.out.println(cla.a); } }
结果:
5
10
结果分析:cla中的a变量被改变,结果输出为10。
类是保存在由jvm分配内存保存在堆中的,当类的引用被传递到方法中后,该方法中对该类内的操作都是通过堆内存来操作的,所以会生效。
不会生效的是如下方式:
package com.csust.wk; class TestClass { int a; } public class FunctionTest1 { public static void change(TestClass c){ /*不会生效的方式*/ c = new TestClass(); c.a = 10; } public static void main(String[] args) { TestClass cla = new TestClass(); cla.a = 5; System.out.println(cla.a); change(cla); System.out.println(cla.a); } }
由于值传递传递的是引用的复制,当将方法中的c引用重新定位到新的类(即不同的内存地址)的时候,对新的类的操作是不会影响到原类的,也就是说,java的值传递的意思是,传递的过程中可以对原引用造成一定的影响,可以改变引用对象中的数据,但是不可以直接操作到该引用,因为java传递过去的不是一个指向源引用的指针,而是原引用的一个复制,这个值传递的概念是成立的,只是由于java对于值传递的特殊处理方式所以导致有的人对该值传递产生一定的质疑。