java引用与C语言指针的区别是什么?

Python010

java引用与C语言指针的区别是什么?,第1张

首先, 在Java中, 不存在引用传递(也就是地址传递)一说, 全部都是值传递, 自然, 在使用对象时实际上都是使用的引用\x0d\x0a\x0d\x0a Java语言明确说明取消了指针,因为指针往往是在带来方便的同时也是导致代码不安全的根源,同时也会使程序的变得非常复杂难以理解,滥用指针写成的代码不亚于使用早已臭名昭著的"GOTO"语句。Java放弃指针的概念绝对是极其明智的。但这只是在Java语言中没有明确的指针定义,实质上每一个new 语句返回的都是一个指针的引用,只不过在大多时候Java中不用关心如何操作这个"指针",更不用象在操作C++的指针那样胆战心惊。\x0d\x0a\x0d\x0a 非也,基本类型数据存放在Stack中,存放的是数据。而产生对象时,只把对象的reference存放在stack中,用于指向某个对象,对象本身存放在Heap中。\x0d\x0a\x0d\x0a 还有, 调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。\x0d\x0a\x0d\x0a 从实现上来讲,引用可以理解为一种受限的指针,引用底层可以采用指针来实现,也可以采用句柄的方式实现。早期jvm一般采用句柄的方式,现在的jvm,比如sun的,IBM的,一般就是用指针来实现。\x0d\x0a\x0d\x0a 不过从语言的角度来将,没有必要把java的引用和C的指针来比较。\x0d\x0a\x0d\x0a 指针是可以进行与整数做加减运算的,两个指针之间也可以进行大小比较运算和相减运算。\x0d\x0a\x0d\x0a 引用不行,只能进行赋值运算。\x0d\x0a\x0d\x0a 当然有区别\x0d\x0a\x0d\x0a A a=new A()\x0d\x0a\x0d\x0a 你可以 a=a+1吗? 指针就可以

实际上,java力图使程序员忘记指针,这包括2个方面:

第一,java限制指针,去除了指针运算。

第二,java从语法上努力隐藏指针,让指向某对象的指针看起来更像那个对象本身!

是的,所有的java书籍都让人忘记了指针这回事,我们仿佛只跟对象打交道。偶尔,会被迫分清引用和

对象的关系。这就是目前的情形。多么好的想法!对象可比那些个不知所以的指针亲和多了!这是一种伟大的抽象!

这里,我们也更愿意把引用和对象混淆。是的,为什么不呢?那样,整个世界都是对象,太好理解了!

可事实上,为了节省内存,java不能把引用(指针)完全废除。要知道,复制一个引用(指针)要比

复制整个对象有效得多!所以我们不得不面对引用和对象共存的事实。

下面我就好好分析分析:

指针已经被抽象成了引用,现在指针不能够随心所欲的运算,并且看起来就像个对象,完全没有了指针

的模样。但它毕竟和对象还是不同的,还要经过一层“转换”(从指向的那个对象里取数据)。如果我们

在引用满天飞的时候总想着这样一层转换,真的是很不舒服。比如:

String key="name"

String value="hyq"

HashMap map=new HashMap()

map.put(key,value)

你得想着:key只是个引用,value也是个引用,map还是个引用,我们刚刚做的是把key和value

这2个引用放进了map(也是个HashMap对象的引用)中,到时候我就可以通过map这个引用取得

里面的对应于key引用的value引用!

你不晕我就服了。

一旦你这样想,你每时每刻都要面对这样的绕口令。因为我们对对象的操作全部要通过引用!java没有提供语法让你直接得到对象!(指的是直接寻址)这一点通过比较原始类型很好理解,int i=8,那么

i就是8,不是什么指针,要先找到放着8那块内存的地址再把8拿出来。这样多直接,多方便啊!

所以,我们对引用最好也这么来理解,就轻松多了。

还是上面的例子,key就是个String,value也是个String,map是个HashMap,我们把key和value

放进map里,将来可以按key取出value。——多简单!

其实,这样的理解是很符合人的思维习惯的,我相信大多数人刚学java时都会自然而然的这么理解,

但是我们一定要注意在什么时候不能这么理解。只要记住什么时候不能这么理解,我们就不会因为

这种“近似”的理解方式而犯错,而同时从这种理解方式里得到了方便和好处。

把引用直接当作对象本身的好处是简单直接,容易理解,而“误差”的地方就在于,假设只有这个引用

可以修改此对象。换句话说,当别的引用修改了对象的时候,我们毫不知情并很感费解。比如:

String name=null

HashMap map=new HashMap()

map.put("name",name)

//do a lot of things

name="hyq"

当我们再从map里取出name的时候,发现它已经被赋值为hyq了!放进去的时候明明是啥都没有啊!

咋就变了讷?

引用到name那个对象的不只你map一个阿!

在同一个函数里出现这种情况还不是很常见,我们一般也不必这么写,更多的是出现在函数调用、传参的时候,这样更加隐蔽,不易发现,也让代码可读性下降。比如:

String name=null

HashMap map=new HashMap()

map.put("name",name)

alterName(name)

在alterName函数里我们修改了name对象,这会直接影响到函数外的map。

所以,当我们把引用和对象故意混淆时,一定要记住什么时候应该分清楚。

对象的使用不外乎以下几种情况:

1

String name=new String("hyq")

然后使用name,引用生命周期一结束,对象失效(无法被取用)了事。这里只有name一个引用指向此对象,随便怎么弄都不会出事。

2

String name=new String("hyq")

String anotherName=name

这里假设只有name会修改对象,并且在anotherName引用此对象前做完所有修改,anotherName只是取用这个对象调用方法。在这种情况下,也不会出事。这也是我们经常遇到的情况,并且一般都是在函数调用传参时出现。注意传参实际上就是String anotherName=name

这里尤其要注意的是2个引用的生命周期:name修改对象的时候另一个引用还没出世,而等它出世后

发现它又不会修改对象,怎一个爽字了得!

3

String name=new String("hyq")

String anotherName=name

代码和上面一样,但是这里要么2个引用都会修改对象,要么只有一个修改但会影响到另一个。这个时候无论如何你不能再把引用当对象了,你必须分清楚它们。你必须小心仔细,不能有丝毫疏忽。

当然,这种写法和风格无论如何是不值得提倡的,若非必要(没办法)请勿模仿!因为必然有一个引用

在不知情的情况下被人修改了对象,等它用的时候会大吃一惊,而这个对象是在什么时候被什么人修改的,极难排查。

(上面例子举得不好,String类是不变类,汗!)

StringBuffer name=new StringBuffer("hyq")

StringBuffer anotherName=name

//do a lot of things

anotherName.append("is my gf")

你可能写得爽,一时痛快就这么写了,你也知道是什么人在什么时候修改了对象,但是别人呢?

要知道,这里可能不是相隔几行代码这么简单,可能是嵌套了好几层函数调用!你把那个anotherName传到第5层函数里面,然后丧心病狂的修改了那个对象,除了天知地知你知,鬼

都看不出来!

学过c/c++,然后学Java的人往往心中有此纠结,java中到底有没有指针?

如果一定要在是或否里选择一个,OK,java中没有指针。

那么,java中的引用(reference)和c/c++中的指针(如无特别说明,后文指针均指c/c++中的指针)究竟有着什么样纠葛不清的关系呢?

在开始之前先说一下c/c++的引用,它跟java的引用完全不是一个东西,c/c++的引用是同一块内存的不同名字。而java的引用是指向一个对象,引用本身也占用了内存。

首先,列举一下能对指针进行的一些常见操作:

1、指向一个对象,如 Person *p = new Person….;int *iv = new int….

2、对指针所指的对象进行操作:P->getAge() (*p).getAge()

3、获取存储在指针中的地址值。

4、将指针指向另外一个对象:Person *p1 = new Person…p = p1 但,不可以*p = p1这样来赋值。

5、删除new的空间,delete p1

6、其它诸多操作

这么多已经足够了,接下来看看java引用能做什么操作。

a、指向一个对象,如Person p = new Person…

b、调用对象的方法,p.getAge()

c、指向另外一个对象,Person p1 = new Person…p = p1

OK,就这么多了。

对于a和1,他们的功能是类似的,但java引用无法指向一个基本变量。。

对于b,java引用和指针就不同了,在这点上,Java reference更像是解引用(dereference)了的指针;或者说java中的.操作符某种程度上等价于指针的->操作符,如果是这样种解释的话,我们无法再对java的reference解引用了。

对c和4,是类同的。

除此,我们无法获取java引用存的地址,我们不能delete,还有很多……

综上,窃以为java的引用可以看成是一个功能受限的指针(或者说被阉割的指针)。另一方面,功能如此受限,它还能叫指针吗?了解了指针和java引用的区别与联系,还需要纠结“java中有没有指针”这个问题吗!