先看下面的一段代码:
package com.ivantian.CoreFengZhuang;
//call by values
//call by address
public class Difference {
int x = 10; // 成员变量
public static void main(String[] args) {
int a = 10;
int b = a;
System.out.println("这是传值引用:");
System.out.println("测试前的数据:");
System.out.println("a的数值是:" + a + " b的数值是:" + b);
a = 20;
System.out.println("测试后的数据:");
System.out.println("a的数值是:" + a + " b的数值是:" + b);
System.out.println();
System.out.println("这是传地址引用:");
Difference diff = new Difference();
Difference diff1 = diff; // 让 diff拥有同样的参考
System.out.println("测试前的数据:");
System.out.println("diff.x = " + diff.x +" diff1.x = " + diff1.x);
diff.x = 100;
System.out.println("测试后的数据:");
System.out.println("diff.x = " + diff.x +" diff1.x = " + diff1.x);
}
}
//执行结果如下
/*
这是传值引用:
测试前的数据:
a的数值是:10 b的数值是:10
测试后的数据:
a的数值是:20 b的数值是:10
这是传地址引用:
测试前的数据:
diff.x = 10 diff1.x = 10
测试后的数据:
diff.x = 100 diff1.x = 100
*/
不错,是和C/C++的一些程序示例是相似的,实际上,在C++中有两种传递参数的方式:传值调用(call by alues) 和 传参考调用(call by reference)的方式,而在Java中只有传值调用。你不仅会好奇的问,上面的例子中diff不是传递的“参考”吗?www.zzzyk.com
对的,此"参考"是Java世界中的参考,与C++中的参考还有所不同。在前面的几篇文章,比如数组,字符串章节都有“参考”一词的出现,若有疑问请及时联系,并可以参考前面的文章。
对上面程序例子的解释如下:
传值引用主要是针对基本数据类型而言。所谓传值引用就是再进行变量的传递过程中,传递的是变量的实际的值,就是实际值的复制。由于一个变量值不会影响另一个变量值的改变,所以操作后的结果不会影响原来的值。
传地址引用主要是针对对象操作,他传递的是一个对象句柄的复制。也就是形成了多个变量操作一个对象的局面,任何一个针对句柄操作的变量,都会影响到其他的变量。
因此我认为:
"在java世界中只存在一种传值调用(Call by value)。其实上面的两种方式传递的都是“值”,对于对象而言只不过传过去的值只是一个对象的地址值,只是所反映出来的现象和"传引用调用"相似罢了,但实质是传值调用。而在C++中,还存在一种传参考调用或者叫做传引用调用(Call by Reference)。"
很多初学者对着两个概念容易混淆。其实笔者也是一样。再看下面的一个程序示例:
还以FindWife为例子。
先上代码:
package com.ivantian.CoreFengZhuang;
// Object's calling by value(s)
// Class Definitions
class Wives{
String name;
Wives(String name){
this.name = name;
}
}
//Testing ,Finding wives
public class FindWives {
//FengJie 之归我所有 很难驾驭
public static void FengJie(Wives w){
w.name = "FengJie";
}
//FuRong 之归我所有 乖巧懂事
public static void FuRong(Wives w){
w = new Wives("FuRong");
}
//main method
public static void main(String[] args) {
//把 FengJie换成 白娘子
Wives wife = new Wives("白娘子");
FindWives.FengJie(wife); //能够 更换成功吗?
System.out.println("My wife will be :" + wife.name);
//把 FuRong 换成 白娘子
Wives wife1 = new Wives("白娘子");
FindWives.FuRong(wife1);//
System.out.println("My wife will be :" + wife1.name);
}
}
执行结果呢?这里先买个关子,下面逐步来分析。
眼下有三大奇女子“FengJie,FuRong,白娘子”供我选择,若是用纳什均衡理论,可以很快作出“最优解”的判断,但是我们不是做经济学研究的。
方案一:
事实上,还是找“白娘子”这样的wife比较不错,白富美,还能上天入地。先让她和FengJie做个比较。FengJie利用她自身的"技能Fengjie()"迫使白娘子wife同意Fengjie w 来参考她的名字,FengJie w 当然高兴了。如图一所示:
图一:wife与w参考同一对象
FengJie()说,我的名字是:FengJie,不容改变。于是白娘子也奈何不了她。如图二:
图二 :将w参考的对象的name指定为:FengJie
在主程序执行完FengJie()后,FengJie()中的对象w就被法海(JVM)给“垃圾回收(GC)”了,输出要取得wife.name并显示出来。其实最后得到的是”白娘子“的对象,但她用的是”FengJie“的名字。不过这样也好,JVM没有机会镇她了.FengJie是江湖没有此人,却流传此人的传说。
FuRong也打算同样的想法来对付白娘子,操作如图三所示:
图三:wife1与参数w参考同一对象
因为FuRong目睹了FengJie的悲惨结局,她自己留了一手,在FuRong()中建立了一个系对象w,并指定给w参考,如图四,
图四:w参考之新建的对象
在主程序执行完FuRong()后,FuRong()中的新建的对象w就被法海(JVM)给“垃圾回收(GC)”了,输出要取得wife1.name并显示出来。其实最后得到的是”白娘子“的对象,也是她自己的名字“白娘子”。可惜FuRong,江湖不再有FuRong的任何传说。
所示,程序执行的结果是:
/*程序执行的结果
My wife will be :FengJie
My wife will be :白娘子
*/