您的位置:首页 > 编程语言 > Java开发

java参数传递机制浅析

2014-04-28 09:46 281 查看
欢迎转载,转载请声明出处!

-----------------------------------------

前言:
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
如果你以为第二次输出testOK,那就错啦,String类的’+‘是经过重载的,编译时会还原成StringBuilder的append操作,并且new了一个StringBuilder对象:
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
  6.2在方法内部调用StringBuffer或StringBuilder的append方法:
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.数组类型作为参数跟传递对象时一样的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: