转载自: http://blog.csdn.net/chdjj/article/details/24619727#comments
前言:
java语言中,参数的传递只有一种机制,那就是值传递。
举例:
下面将通过几个例子来说明java中的参数传递机制,这些例子基本涵盖了所有参数传递的情况。
1.基本数据类型:
- public static void testBase(int i)
- {
- i = 2;
- }
测试:
- int i = 10;
- System.out.println(i);//10
- testBase(i);
- System.out.println(i); //10
结果当然很显然都是10,因为 基本数据类型传递的是值的一份拷贝(副本) ,对副本操作不影响原始值。
2.对象:
2.1.对参数重新赋值:
- public static void testObj(Object o)
- {
- o = new Object();
- }
测试:
- Object o = new Object();
- System.out.println(o);// java.lang.Object@1ff61bcf
- testObj(o);
- System.out.println(o);//java.lang.Object@1ff61bcf
方法中的参数只是原始对象的一份拷贝,更准确的讲是地址的一份拷贝,故而对其进行重新赋值并不会影响原始对象。
2.2.改变对象内部数据:
- public class S
- {
- private Object o = new Object();
- private int i = 2;
- public Object getO()
- {
- return o;
- }
- public void setO(Object o)
- {
- this.o = o;
- }
- public int getI()
- {
- return i;
- }
- public void setI(int i)
- {
- this.i = i;
- }
- }
- public static void testA(S s)
- {
- s.setI(100);
- s.setO(new Object());
- }
测试:
- S s = new S();
- System.out.println(s.getI()+","+s.getO());// 2,java.lang.Object@11b75be2
- testA(s);
- System.out.println(s.getI()+","+s.getO());//100,java.lang.Object@1cf15b84
因为对象作为参数传递的是对象的引用地址(注意,这是值传递),故参数所指的对象和原始引用 所指的对象都是堆中的 同一个对象,故在测试方法中修改对象内容会改变对象的数据。
试试自己分析这个例子(跟上面是一样的):
- package test;
- public class A
- {
- int t = 6;
- Object obj = new Object();
- public static void main(String[] args)
- {
- A a = new A();
- a.func(a.t,a.obj);//问t和obj的值是否变化,答案:不变化
- }
- public void func(int t,Object obj)
- {
- t = 7;
- obj = null;
- }
- }
3.数组:
3.
1.对参数重新赋值:
- public static void testArr(int[] arr)
- {
- arr = null;
- }
- int[] arr = {1,2};
- System.out.println(arr[0]);//1
- testArr(arr);
- System.out.println(arr[0]); //1
传递机制跟对象一样,也是传递的对象地址,故而也不改变原始值。
3.2.改变参数内部数据:
- public static void testArr(int[] arr)
- {
- arr[0] = 100;
- }
- int[] arr = {1,2};
- System.out.println(arr[0]);//1
- testArr(arr);
- System.out.println(arr[0]);//100
结果无须解释了吧。
4.基本数据类型的包装类型:
其实跟基本类型是一样的。
- public static void testWrapper(Float f)
- {
- f = 100.0f;
- }
- Float f = 12.0f;
- System.out.println(f);//12.0
- testWrapper(f);
- System.out.println(f);//12.0
5.
【重点】
字符串:
字符串作为参数的情形比较特殊。
5.1.对参数重新赋值:
- public static void testStr1(String str)
- {
- str = "testOK";
- }
- String str = "test";
- System.out.println(str);//test
- testStr1(str);
- System.out.println(str);//test
5.2.对参数执行替换、连接等操作:
- public static void testStr2(String str)
- {
- str = str.concat("OK");
- str = str.toUpperCase();
- }
- String str = "test";
- System.out.println(str);//test
- testStr2(str);
- System.out.println(str);//test
也是对str的重新赋值,不改变原始串.
5.3.对参数执行+的操作
- public static void testStr3(String str)
- {
- str += "OK";
- }
- String str = "test";
- System.out.println(str);//test
- testStr3(str);
- System.out.println(str);//test
- str += "OK";
- str = new StringBuilder(str).append("OK").toString();//编译时会还原成这样
显然也是对副本重新赋值,并不影响原始的对象。
使用javap -c反编译一下会很直观:
6.StringBuffer或StringBuilder作为参数:
6.1重新赋值
- public static void testStringBuilder(StringBuilder sb)
- {
- sb = new StringBuilder("testOK");
- }
- StringBuilder sb = new StringBuilder("test");
- System.out.println(sb.toString());//test
- testStringBuilder(sb);
- System.out.println(sb.toString());//test
- public static void testStringBuilder(StringBuilder sb)
- {
- sb.append("OK");
- }
- StringBuilder sb = new StringBuilder("test");
- System.out.println(sb.toString());//test
- testStringBuilder(sb);
- System.out.println(sb.toString());//testOK
7.交换问题
经过上面的例子,相信对java参数传递机制比较清楚了,所以请不要再写这样的代码了:
- public static void swap(Integer a, Integer b)
- {
- Integer temp = a;
- a = b;
- b = temp;
- }
总结:
1.如果参数是基本数据类型(包括对应的包装类型),那么参数传递时只是原始值的一份拷贝或者叫副本,对副本操作并不影响原始值;
2.如果参数是对象(引用类型),那么参数传递时传递的是对象的地址的一份拷贝,所以对对象内部属性的操作会改变原始对象相应值,但是对该参数进行重新赋值并不会影响原始对象;
3.String类型作为参数进行传递时,传递的也是地址。但是String类比较特殊,对参数进行concat,replace,’+‘等操作时不影响原始的串,对参数重新赋值当然也不影响原始字符串。
4.数组类型作为参数跟传递对象时一样的。