java参数传递机制浅析

转载自: http://blog.csdn.net/chdjj/article/details/24619727#comments

前言:
java语言中,参数的传递只有一种机制,那就是值传递
举例:
下面将通过几个例子来说明java中的参数传递机制,这些例子基本涵盖了所有参数传递的情况。
1.基本数据类型:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testBase(int i)     
  2.  {  
  3.        i = 2;  
  4.  }  

 测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int i = 10;  
  2. System.out.println(i);//10  
  3. testBase(i);  
  4. System.out.println(i);  //10  

结果当然很显然都是10,因为 基本数据类型传递的是值的一份拷贝(副本) ,对副本操作不影响原始值。

2.对象:
    2.1.对参数重新赋值:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testObj(Object o)  
  2. {  
  3.    o = new Object();  
  4. }  

测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Object o = new Object();  
  2. System.out.println(o);// java.lang.Object@1ff61bcf    
  3. testObj(o);  
  4. System.out.println(o);//java.lang.Object@1ff61bcf  

方法中的参数只是原始对象的一份拷贝,更准确的讲是地址的一份拷贝,故而对其进行重新赋值并不会影响原始对象。

  2.2.改变对象内部数据:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class S  
  2. {  
  3.     private Object o = new Object();  
  4.     private int i = 2;  
  5.       
  6.     public Object getO()  
  7.     {  
  8.         return o;  
  9.     }  
  10.     public void setO(Object o)  
  11.     {  
  12.         this.o = o;  
  13.     }  
  14.     public int getI()  
  15.     {  
  16.         return i;  
  17.     }  
  18.     public void setI(int i)  
  19.     {  
  20.         this.i = i;  
  21.     }  
  22. }  
测试方法:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testA(S s)  
  2. {  
  3.    s.setI(100);  
  4.    s.setO(new Object());  
  5. }  

测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. S s = new S();  
  2. System.out.println(s.getI()+","+s.getO());// 2,java.lang.Object@11b75be2    
  3. testA(s);  
  4. System.out.println(s.getI()+","+s.getO());//100,java.lang.Object@1cf15b84  

因为对象作为参数传递的是对象的引用地址(注意,这是值传递),故参数所指的对象和原始引用 所指的对象都是堆中的 同一个对象,故在测试方法中修改对象内容会改变对象的数据。

试试自己分析这个例子(跟上面是一样的):
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package test;  
  2. public class A  
  3. {  
  4.     int t = 6;  
  5.     Object obj = new Object();  
  6.     public static void main(String[] args)  
  7.     {  
  8.         A a = new A();    
  9.         a.func(a.t,a.obj);//问t和obj的值是否变化,答案:不变化  
  10.     }  
  11.     public void func(int t,Object obj)  
  12.     {  
  13.         t = 7;  
  14.         obj = null;  
  15.     }  
  16. }  
3.数组:
    3. 1.对参数重新赋值:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testArr(int[] arr)  
  2.   {  
  3.       arr = null;  
  4.   }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int[] arr = {1,2};  
  2. System.out.println(arr[0]);//1  
  3. testArr(arr);  
  4. System.out.println(arr[0]);  //1  
传递机制跟对象一样,也是传递的对象地址,故而也不改变原始值。
      3.2.改变参数内部数据:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testArr(int[] arr)  
  2.    {  
  3.        arr[0] = 100;  
  4.    }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int[] arr = {1,2};  
  2. System.out.println(arr[0]);//1  
  3. testArr(arr);  
  4. System.out.println(arr[0]);//100  
结果无须解释了吧。
4.基本数据类型的包装类型:
     其实跟基本类型是一样的。
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testWrapper(Float f)  
  2. {  
  3.      f = 100.0f;  
  4. }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Float f = 12.0f;  
  2. System.out.println(f);//12.0  
  3. testWrapper(f);  
  4. System.out.println(f);//12.0  
5. 【重点】 字符串:
字符串作为参数的情形比较特殊。
     5.1.对参数重新赋值:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testStr1(String str)  
  2. {  
  3.     str = "testOK";  
  4. }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. String str = "test";         
  2. System.out.println(str);//test  
  3. testStr1(str);  
  4. System.out.println(str);//test  
根据前面的思路,字符串也是对象,参数拷贝的是对象的地址,在方法内部将参数指向另一个堆对象并不影响原始对象引用的指向。

 5.2.对参数执行替换、连接等操作:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testStr2(String str)     
  2. {  
  3.     str = str.concat("OK");  
  4.     str = str.toUpperCase();  
  5. }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. String str = "test";  
  2. System.out.println(str);//test  
  3. testStr2(str);  
  4. System.out.println(str);//test  

也是对str的重新赋值,不改变原始串.
    5.3.对参数执行+的操作
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testStr3(String str)  
  2.     {  
  3.         str += "OK";  
  4.     }  
测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. String str = "test";  
  2. System.out.println(str);//test  
  3. testStr3(str);  
  4. System.out.println(str);//test  
如果你以为第二次输出testOK,那就错啦,String类的’+‘是经过重载的,编译时会还原成StringBuilder的append操作,并且new了一个StringBuilder对象:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. str += "OK";  
  2. str = new StringBuilder(str).append("OK").toString();//编译时会还原成这样  
显然也是对副本重新赋值,并不影响原始的对象。
使用javap -c反编译一下会很直观:

6.StringBuffer或StringBuilder作为参数:
     6.1重新赋值
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testStringBuilder(StringBuilder sb)  
  2. {  
  3.      sb = new StringBuilder("testOK");  
  4. }  
 测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. StringBuilder sb = new StringBuilder("test");  
  2. System.out.println(sb.toString());//test  
  3. testStringBuilder(sb);  
  4. System.out.println(sb.toString());//test  
   6.2在方法内部调用StringBuffer或StringBuilder的append方法:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void testStringBuilder(StringBuilder sb)  
  2. {  
  3.     sb.append("OK");  
  4. }  
 测试:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. StringBuilder sb = new StringBuilder("test");  
  2. System.out.println(sb.toString());//test  
  3. testStringBuilder(sb);  
  4. System.out.println(sb.toString());//testOK  
7.交换问题
    经过上面的例子,相信对java参数传递机制比较清楚了,所以请不要再写这样的代码了:
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public static void swap(Integer a, Integer b)  
  2. {  
  3.  Integer temp = a;  
  4.  a = b;  
  5.  b = temp;  
  6. }  
这根本不能交换两个数.



总结:
1.如果参数是基本数据类型(包括对应的包装类型),那么参数传递时只是原始值的一份拷贝或者叫副本,对副本操作并不影响原始值;
2.如果参数是对象(引用类型),那么参数传递时传递的是对象的地址的一份拷贝,所以对对象内部属性的操作会改变原始对象相应值,但是对该参数进行重新赋值并不会影响原始对象;
3.String类型作为参数进行传递时,传递的也是地址。但是String类比较特殊,对参数进行concat,replace,’+‘等操作时不影响原始的串,对参数重新赋值当然也不影响原始字符串。
4.数组类型作为参数跟传递对象时一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值