文档章节

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

osDaniel
 osDaniel
发布于 2013/12/02 20:46
字数 1387
阅读 1009
收藏 9

用过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中失败!

这是个悲伤的故事。。。

© 著作权归作者所有

osDaniel
粉丝 6
博文 37
码字总数 17120
作品 0
广州
私信 提问
浅析:Java与C++的主要区别

Java区别于C++ 表面看来两者最大的不同在于Java没有指针,或者说,Java满地都是指针。对于编程者而言Java的这种设计是安全且更易用的。说Java满地是指针的原因在于它把指针的功能隐藏了,其实...

Ace☞Tseng
2012/10/09
327
0
Android JNI(一)——NDK与JNI基础

本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Native相互调用 Android JNI学习(四)——JNI的常用方法...

隔壁老李头
2018/05/09
0
0
Jave语言和C#语言

Java语言与其他语言的区别 1.Java不支持指针,因为指针是C++程序中许多很难处理的错误源,在Java中,对象总是通过引用来处理 2.Java不支持运算符重载 3.Java完全是面向对象 Java与C#的比较 ...

晨曦之光
2012/04/24
231
0
java中值传递的理解,C++中传值传递、引用传递和指针方式的理解

通过对参考文献中两篇文章的理解消化,自己运行测试分析总结如下: java的值传递理解: 代码1: public class Test { /** * @param args */ public static void main(String[] args) { Stri...

Nob
2014/09/20
1K
1
用 JNI 进行 Java 编程(2)

从 Java 程序调用 C/C++ 代码 概述 当无法用 Java 语言编写整个应用程序时,JNI 允许您使用本机代码。在下列典型情况下,您可能决定使用本机代码: 希望用更低级、更快的编程语言去实现对时间...

Jerikc
2012/10/08
193
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS-启用SFTP

创建用户组及用户 $ groupadd sftp $ useradd -g sftp -s /sbin/nologin -d /home/sftp sftp 设置密码 $ passwd sftp 输入密码(123456) 确认密码 修改sshd_config文件 $ vim /etc/ssh/sshd_......

自由人生-ZYRS
20分钟前
11
0
这个IM项目没时间搞了,开源算了。10万并发,基于golang。

先上效果 安装方法 本系统升级到golang1.12,请开启如下支持 #开启go mod支持export GO111MODULE=on#使用代理export GOPROXY=https://goproxy.io 1.下载项目 git clone https://github.c...

非正式解决方案
24分钟前
6
0
Mysql基本操作

查看mysql中已经有的数据库 二、删除已经有的数据库school 三、创建新数据库myschool 四、进入到myschool中 五、查看myschool库中所有的表 六、新建一张student表 七、查看student表结构 八、...

愚蠢的土豆
24分钟前
8
0
经典检索算法:BM25

BM25算法是一种常见用来做相关度打分的公式 思路比较简单,主要就是计算一个query里面所有词和文档的相关度, 然后在把分数做累加操作 而每个词的相关度分数主要还是受到tf/idf的影响 其实就...

Java搬砖工程师
31分钟前
5
0
详解mycat+haproxy+keepalived搭建高可用负载均衡mysql集群

概述 目前业界对数据库性能优化普遍采用集群方式,而oracle集群软硬件投入昂贵,mysql则比较推荐用mycat去搭建数据库集群,下面介绍一下怎么用mycat+haproxy+keepalived搭建一个属于mysql数据...

小致Daddy
31分钟前
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部