您的位置:

java指针,Java指针异常

本文目录一览:

java中指针怎么理解?

实际上,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层函数里面,然后丧心病狂的修改了那个对象,除了天知地知你知,鬼

都看不出来!

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

java引用与C语言指针的区别有以下几方面:

1、现象

指针在运行时可以改变其所指向的值,而引用一旦和某个对象绑定后就不再改变,总是指向最初的对象。

2、编译

程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变指向的对象(指针变量中的值可以改),而引用对象不能改。

3、类型

引用其值为地址的数据元素,java封装了的地址,可以转成字符串查看,长度可以不必关心;C指针是一个装地址的变量,长度一般是计算机字长,可以认为是个int。

4、内存占用

所占内存:引用声明时没有实体,不占空间。C指针如果声明后会用到才会赋值,如果用不到不会分配内存。

5、内存溢出

JAVA引用的使用权限比较小,不会产生内存溢出。C指针是容易产生内存溢出的,所以程序员要小心使用,及时回收。

6、本质

JAVA中的引用和C中的指针本质上都是想通过一个别名,找到要操作的目标(变量对象等),方便在程序里操作。所不同的是JAVA的办法更安全,使用更加方便些,但没有了C的灵活,高效。

java中指针操作是什么意思

众所周知,在java里面是没有指针的。那为何此处还要说java里面的“指针”呢?我们知

道在C/C++中,指针是指向内存中的地址,该地址就是存储变量的值。该地址所存储的变量值是“公有”的,此处的“公有”是对于拥有该地址的变量而言。它

们都可以访问该地址的内容,并且可对其就行修改,一经修改则所有指向该地址的变量值也将改变。那么在Java里面何来的指针?在java里面没有指针的定

义。但是java里面的“指针”无处不在。下面将进行介绍。我们知道JAVA里面用的最多的就是对象,我们经常将一个对象传递给不同的变量,例如:

Student s1 = new Student();

Student s2 = s1;

此时s1和s2是指向同一个对象的,也就是s1和s2引用同一个对象,我们知道java里面创建一个对象是存放在堆的,当我们new一个对象的时候其实是

在堆中开辟了一个存储该对象的空间,返回是的存储该对象在堆中的地址,所以在java中我们所谓的对象引用就是指针,只是没有像C/C++中给出了一个明

确的定义。java是为了避免指针带来的使用上的麻烦,所以就使用对象的引用来代替了指针。上面的例子中,当我们在s1中进行修改Student中的属性

的时候,那么当s2取Student中属性的值的时候便是取得了s1修改后的值,这是因为s1和s2是指向堆中的同一块内容,所以只要其中一个变量修改了

堆中的值,则其他的变量将取得堆中最后更新的值。所以我们可以知道,s2=s1并不是又在堆中创建了一块内存,而只是把一个对象的地址赋给了s2,此时还

是只是创建了一个对像,而不是两个。在实际开发中会经常碰到这些,假设创建一个MapString,Object类型的对象,它的

value是一个对象,而key是一个字符串,定义如下:

class Student{

private String name;

private int age;

public void setAge(int age)

{

this.age = age;

}

public Student(String name)

{

this.name = name;

}

}

MapString,Student studentMap = new HashMapString,Student();

Student s1 = new Student("张三");

Student s2 = new Student("李四");

studentMap.put(s1.name,s1);

studentMap.put(s2.name,s2);

此处是一个学生姓名对应了一个

学生,所以此处的Map的key是学生姓名,value是一个学生对象。那么就是将一个Student对象的引用赋给了Map中key所对应的

value,所以当程序在别处改变了s1/s2的值后,不必将s1和s2的信息更新到studentMap中,studentMap就会获得key所对应

的value最新的值,例如:在程序的某处我们将s1的age修改成了“23”,我们不必将s1的最新信息更新到studentMap

中,studentMap就会获得s1的最新值。这是因为已经将s1对象的引用赋给了studentMap中张三所对应的value,也就是将对象在堆中

的地址赋给了value。所以只要s1一更新,studentMap就可以获得最新的值。

有时候这种情况会影响我们程序的执行和我们想想的会有偏差,当我们需要保存一个对象在某时刻的状态时,按照一般的理解是将此时的对象赋给一个变量来进行

存储,但是在java里面这样是行不通的!因为这样直接将该对象赋给另一个变量只是将该对象的引用赋给了此变量,该变量的值并不能保持在此刻该对象的值,

会随着程序的执行,该对象的改变而变化。所以达不到我们的目的。下面就举个例子来说明解决该现象:

class Student{

private String name;

private int age;

public void setAge(int age)

{

this.age = age;

}

public Student(String name)

{

this.name = name;

}

public Student(Student student)

{

this.name = student.name;

this.age = student.age;

}

}

上面还是student类,基

本和上面一样,只是多添加了一个构造函数——Student(Student

student),为什么要多加这样一个函数呢?这就是为了满足我们上面的需求(保存对象某个时刻下的状态),我们知道直接将一个对象赋给一个变量会存在

对象的引用,不能保存对象某时刻的状态。同时也知道要想保存一个对象就要在堆中开辟一个空间,用于存放我们的对象。其实上面的需求可以看做当我们要保存某

时刻下对象的状态,其实就是该对象的状态不会随以后对象的变化而变化,所以何不将当前某时刻下对象的状态属性全部都复制到一个新的对象中去!这样保存下来

的属性就不会受以后对象的变化而变化了。就上面的例子,举例说明:

Student s1 = new Student("王麻子");

s1.age=23;

........

//此时要保存s1此刻的状态

Student s2 = new Student(s1);

此时s1和s2就不是指向堆中的一个地址了,因为s2不是直接将s1赋给它的,而是通过new出来的!上面说了new可以在堆中开辟一个存储当前new的

对象的空间。这种操作可以实现将s1中的状态全都转移到s2中,所以在值的方面看s2和s1此时是一样的,但是在堆中确实不一样的,s1!=s2,因为

s1和s2的hashcode不一样!但是s1.name.equal(s2.name)==ture,s1.age=s2.age。这不就实现了保存某

个对象某个时刻下的状态了吗?而切不会在受程序执行的影响!

到此已全部介绍完有关java“指针”,其实java“指针”就是对象的引用,而对象就是存放在堆中的。我们知道java中的内存分为堆内存(heap)

和栈内存(stack)。堆就是用来存放对象的,而栈则是存放一些数据基本类型的值,如int,float,double,char.......。