用过java和C++的同学都知道在二者中均有引用的概念。但是这两个概念所代表的并不相同。
首先了解C++ 中引用的含义:“引用”即“别名”。C++中的引用代表的就是实际的存储空间。对其进行操作就是对存储空间进行操作。
而在Java中的引用:可以看做是C语言中的“指针”或者“地址”。对java中引用的属性(即指针指向的存储空间)进行操作才是有效的。
参考http://blog.csdn.net/wzy_1988/article/details/16886337:
“
java内存分配中的栈
java内存分配的堆
对于概念有所了解了之后,主要来看看我们经常容易困惑的地方——引用传参:
1)Java引用作为函数(方法)参数
Java的方法参数只是传值,引用作为参数使用时,会给函数内引用的值的COPY,所以在函数内交换两个引用参数是没有意义的,因为函数交换的是参数的COPY值;但是在函数内改变一个引用参数的属性是有意义的,因为引用参数的COPY值指向的对象和原引用指向的是同一个对象。
2)C++引用作为函数参数
由于C++引用传进去的就是“别名”,所以在函数内对其进行的全部操作都将直接作用于实际的对象存储空间上。
产生这个困惑的原因很可能是涉及到在函数(方法)中进行malloc(new)新的堆空间有关。其实这是一个比较有意思的问题。
我们在新建一棵树的时候,经常都会需要在新建函数(方法)中进行malloc(new)。当然,你可以使用新建一个节点就作为函数(方法)返回值进行返回。但是,一般人的思维很可能是直接在函数里面malloc(new),然后直接赋给传入的代表树的参数(T)。这种一般人的思维方法大部分都是受到了严蔚敏《数据结构》的“荼毒”,而有没有弄懂引用在Java和C++代表的不同意义而产生的错误。
诚然,我们在C++中这样来做是没有问题的(参考严蔚敏《数据结构(C语言版)》P131),传入了个BiTree &T然后(T = (BiTNode *)malloc(...)),很开心,测试一下OK了。
然后,在用Java写树的数据结构是还是这么干,就出问题了。其主要的错误原因是:Java中引用作为传参只是传入个引用的COPY,这样的在(T = new ...)之后,方法一结束,这个作为引用的COPY就会被抹去,而在方法中的new对象由于没有引用(没人指向它)也将作为垃圾被回收掉。
我们注意下其中涉及一个很有趣的问题,这个问题是有关C语言中的malloc和JVM中的new的对象存储空间的:
malloc和new产生的对象存储都是发生在堆中的,而非栈。
而C++和Java的引用(包括引用COPY)都是在栈中的。
这么说,其实它们的存储结构是一样的,但是却由于Java传入的引用并非真的引用,只是引用的COPY(有点像“狸猫换太子”),导致C++的树实现方式能够实现,而类似地应用到Java中失败!
这是个悲伤的故事。。。
来源:oschina
链接:https://my.oschina.net/u/1401385/blog/180872