A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黄玉昆 黑马帝   /  2013-2-8 09:41  /  1270 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 黄玉昆 于 2013-2-8 13:45 编辑

数组在内存中是如何被分配的,A[] a = new A[10],这一条语句又是怎么在内存中执行的,昨晚一直想着自己写的代码出现空指针异常的这句话,
我也在网上查了,看到别人相对较好的文章中说“空指针异常发生在对象为空,但是引用这个对象的方法上。”(地址:http://blog.csdn.net/wangkr111/article/details/7830079 )
发生在对象为空,那么说,对象是存在状态的,只不过它其中的值为空。我想着这句话,突然觉得是这样的,如图。
测试出空指针异常(Null.PointerException)代码如下
  1. class Demo0
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 Student[] s = new Student[10];
  6.                 for (int i=0;i<s.length;i++)
  7.                 {
  8.                         s[i].name = (String)("a " + i);
  9.                         s[i].setId(i);
  10.                         System.out.println(s[i].name + "的ID:" + s[i].getId());        
  11.                 }
  12.         }
  13. }

  14. class Student
  15. {
  16.         String name;
  17.         private int id;
  18.         Student(String name,int id)
  19.         {
  20.                 this.name = name;
  21.                 this.id = id;
  22.         }
  23.         public int getId()
  24.         {
  25.                 return id;
  26.         }
  27.         public void setId(int id)
  28.         {
  29.                 this.id = id;
  30.         }

  31. }
复制代码
对于两张图片:
第一张:只是将数组这个对象的地址值赋给了栈内存中引用型变量,而此时,每个引用型变量(即a[0]..a[9])都还没有指向堆内存中的值为空的对象呢。
所以当在运行上面的代码,就会出现空指针异常,因为还没指向这个操作。但是是存在状态为空的对象的。
第二张:当给每一个元素赋值的时候,在堆内存中的对象重新赋值,不再是null了,这时数组中的元素就可以指向堆内存中已经重新赋值的对象了。
还有一点要说明的,就是内存中存储的都是数据,这些都是形象化的东西,可能我的这种理解不太准确,如果我的理解不是很正确,在此求正解。谢谢

数组内存分配1.PNG (19.81 KB, 下载次数: 25)

数组内存分配1.PNG

数组内存分配2.PNG (21.34 KB, 下载次数: 25)

数组内存分配2.PNG

评分

参与人数 1技术分 +1 收起 理由
李培根 + 1 赞一个!

查看全部评分

6 个回复

倒序浏览
这样明显是空指针啊 因为A是一个复杂类型 所以没有缺省值,不像 int float char...这些基本类型,有缺省值 0 或0.0f ,复杂类型的缺省值是null  A[] a = new A[10];其实 内存中实际上是 开辟一块可以存放10个A的对象的空间,里面存放着10个缺省值 null 自然空指针啊
回复 使用道具 举报
你数组的那些A[0] A[1] 等等不应该在栈内存,因为那些A[0] A[1] 等等是属于new A[]的。

好比new Student(),会在堆内存开辟个空间给new Student(),而这个new Student()的类所有的成员变量也在开辟给new Student()的空间里面,外部可以通过各种途径方法给内部成员更改值。

这些数组A[0] A[1] 等等也应该是new A[]的成员,所以也应该在堆内存里。


按照你给的程序,到了s[i].name = (String)("a " + i);这一句,由于数组里每个角标的数组的值都是null   
null.name= (String)("a " + i)   明显不可以,空值怎么能调用name呢
同理下面的setid()方法也是


heima11.JPG (53.32 KB, 下载次数: 22)

heima11.JPG
回复 使用道具 举报
黄鸿达 发表于 2013-2-8 11:25
你数组的那些A[0] A[1] 等等不应该在栈内存,因为那些A[0] A[1] 等等是属于new A[]的。

好比new Student() ...

恩啊,确实有道理,我会在好好理解理解的,想一想,这数组到底是怎么被分配的。很感谢你啊。
回复 使用道具 举报
黄鸿达 发表于 2013-2-8 11:25
你数组的那些A[0] A[1] 等等不应该在栈内存,因为那些A[0] A[1] 等等是属于new A[]的。

好比new Student() ...

不过,我还是觉得只要是引用型变量就是在栈内存中的。至于是不是我的观点错误,我会也会继续学习关于数组方面的知识的,一定要弄明白才行。
回复 使用道具 举报
本帖最后由 王昕 于 2013-2-8 13:30 编辑

给你截个书上的图吧。



灰色是在堆上的意思,一个圈里是一个对象,箭头就是这个引用指向这个对象。
第一个图的What's missing?Dogs!We have an array of Dog references,but no actual Dog objects!就是回答你的问题。
第三个图是另一个程序里比较复杂的情况。
回复 使用道具 举报
王昕 发表于 2013-2-8 13:26
给你截个书上的图吧。

不错的图,谢谢分享给我
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马