Java中的引用和C++中引用的区别

眉间皱痕 提交于 2019-12-04 03:35:35

用过java和C++的同学都知道在二者中均有引用的概念。但是这两个概念所代表的并不相同。

首先了解C++ 中引用的含义:“引用”即“别名”。C++中的引用代表的就是实际的存储空间。对其进行操作就是对存储空间进行操作。

而在Java中的引用:可以看做是C语言中的“指针”或者“地址”。对java中引用的属性(即指针指向的存储空间)进行操作才是有效的。

参考http://blog.csdn.net/wzy_1988/article/details/16886337

java内存分配中的栈

在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配

当在一段代码块定义一个变量时,java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用


java内存分配的堆

堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机的自动垃圾回收器来管理

在堆中产生了一个对象或数组后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相等于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称

引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new产生数组或对象的语句所在的代码块之外,数组和对象本身占据的内存不会释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在使用,但仍然占据内存空间不不放,在随后的一个不确定的时间垃圾回收器收走(释放掉)。这也是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中失败!

这是个悲伤的故事。。。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!