这是个比较简单的问题,但是确实比较容易迷惑人,也迷惑了一部分人。
首先我说一下我的观点,由于.net和java有某些惊人的相似,所以这个问题的结果在.net和java中结果完全一样。
1。默认情况下,不管什么参数(值类型,引用类型),都是传值。
2。要传引用必须制定关键字byref,ref,out等。 这个东西好像java没有。所以java中swap两个对象的值,你需要想其他的办法解决。
看看两个例子:
public static void MySwap(StringBuilder sSwapA, StringBuilder sSwapB)
{
StringBuilder c;
c=sSwapA;
sSwapA=sSwapB;
sSwapB=c;
}
public void testStrb(StringBuilder sAppend)
{
sAppend.Append("Hello");
}
StringBuilder a =new StringBuilder( "a");
StringBuilder b =new StringBuilder ( "b");
MySwap(a,b);
Console.WriteLine("a={0},b={1}",a,b);
testStrb(a);
Console.WriteLine("a={0}",a);
看看结果:
a,b
aHello
这两个结果初看起来好像有点不可思议,既然传引用为什么,swap交换不了,既然传值为什么append能添加。
其实结果一点也不奇怪。
首先要明白几个概念:
1。引用。
在.net和java中,类型分值类型和引用类型。引用类型实例通过对象的引用访问。简单点说,一个实例相当于一个内存块,可以建立多个引用指向同一个实例(内存块)。好像文件和文件的快捷方式一样。
引用是一种数据类型,保存了对象在内存中的地址,这种类型即不是我们平时所说的简单数据类型也不是类实例(对象);
不同的引用可能指向同一个对象,换句话说,一个对象可以有多个引用,即该类类型的变量。
2. 参数是如何传递的
其实很简单,参数的传递过程就是普通的付值过程。我们再来分析下上面的调用过程:
MySwap(a,b);
把这个拆开来应该就是:
StringBuilder sSwapA=a; // sSwapA和a是两个引用,指向同一个实例(内存块a)
StringBuilder sSwapB=b; // sSwapB和b是两个引用,指向同一个实例(内存块b)
明白这个很重要,这里是关键,这里明白了,其他就能想明白了。
2. 交换的过程
我们继续往下走:
StringBuilder c; // 空引用
c=sSwapA; // c和sSwapA指向同一实例(内存块a)
sSwapA=sSwapB; // sSwapA和sSwapB指向同一实例(内存块b)
sSwapB=c; // sSwapB和c指向同一实例(内存块a)
我们看交换后的结果:
a和sSwapB指向同一实例(内存块a)
b和sSwapA指向同一实例(内存块b)
swap函数忙活了半天,结果和a,b一点关系都没有,而只是交换了sSwapA和sSwapB的指向。
总结:
1。引用好像文件的快捷方式,其内容很简单,不过一个内存地址而已。引用的拷贝相当于两个引用指向同一个地址。
2。string 类型,有点特殊,因为它有一个特性叫恒定性,其内容不能更改。
比如:
String a="hello"; //a指向 "hello"这个实例
a="world"; //a指向新建实例 "world" 相当于 a=new String("world")
因为经常碰到,string作为参数,而函数里面改变值之后,外面的值没有改变的情况。
public void testStr(String sTest)
{
sTest="Hello";
}
这个函数是不能改变String的值的,其他的引用类型都可以,相信稍微分析下,就能明白。