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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

  1. <font size="1">class Person
  2. {
  3.    String name;
  4.    Person(String name)
  5.    {
  6.       this.name = name;
  7.    }
  8.    //...
  9. }
  10. //定义一个子类Student
  11. class Student extends Person
  12. {
  13.    String name;
  14.    private int id;
  15.         Student(String name,int id)
  16.         {
  17.                 super(name);
  18.                 this.id = id;
  19.         }
  20.         public int getId()
  21.         {
  22.                 return id;
  23.         }
  24.         public void setId(int id)
  25.         {
  26.                 this.id = id;
  27.         }

  28. }
  29. class DuotaiDemo
  30. {
  31.         public static void main(String[] args)
  32.         {
  33.                 //第一个
  34.                 Person p = new Person("小明");
  35.                 p = null;
  36.                 System.out.println(p);
  37.                 //----------------------
  38.                 //第二个
  39.                 //Person变量可以引用Person的对象,也可以引用它的子类对象
  40.                 Student stu = new Student("大明",0001);
  41.                 Person[] per = new Person[10];
  42.                 per[0] = stu;
  43.                 //第三个
  44.                 Student[] student = new Student[2];
  45.                 //将student转换成Person[]是合法的
  46.                 Person[] person = student;
  47.                 person[0] = new Person("小黑");//给person[0]赋Person类型的值
  48.                 student[0].setId(0002);
  49.                 System.out.println(student[0].name + "的id是" + student[0].getId());
  50.         }
  51. }</font>
复制代码
对于第一个:
将p = null,是p不再指向new出的“小明”这个对象了呢?还是说new出的这个“小明”也随之在内存中消亡了呢?还是说要等内存自动在某个时候消亡呢?
对于第二个:
我们说多态是表示事物的多种形态,那么,这里的多种形态,是不是不能同时具备呢?
上面的代码中,per[0] = stu后,它们引用的是同一个对象,是("大明",0001)这个对象,那么是不是Per[0]就不在指向new Person[10]其中的第一个对象(虽然为null)了呢?
对于第三个:
Person[] person = student;这个语句中,应该是指向的同一个类型的数组(应该是Person[]这个数组吧?),那么现在,student是Student[]数组的类型呢?还是Person[]数组的类型呢?
1、如果是Student[]数组的类型,那么下面的student[0].setId(0002);这个方法是没错的,但是就不是和Person[0]指向相同数组了,

是不是这时候已经将Person[] person = student;这句的行为覆盖掉了呢?
2、如果是Person[]数组的类型,那么下面的student[0].setId(0002);这个方法是不成立的,因为编译时虽然可以通过,但是运行后会报错,如下:

希望大家能帮忙解答清晰。


多态测试.png (5.08 KB, 下载次数: 51)

多态测试.png

评分

参与人数 1技术分 +1 收起 理由
Rancho_Gump + 1

查看全部评分

45 个回复

倒序浏览
本帖最后由 王昕 于 2013-2-7 14:02 编辑

对于第一个:
将p = null,是p不再指向new出的“小明”这个对象了呢?还是说new出的这个“小明”也随之在内存中消亡了呢?还是说要等内存自动在某个时候消亡呢?
等到内存不够的时候会被垃圾收集器(GC)回收,不管什么时候被回收,反正你已经找不到它了,想用也用不到了,对你来说它已经挂了,只等内存不够被回收。
对于第二个:
我们说多态是表示事物的多种形态,那么,这里的多种形态,是不是不能同时具备呢?
上面的代码中,per[0] = stu后,它们引用的是同一个对象,是("大明",0001)这个对象,那么是不是Per[0]就不在指向new Person[10]其中的第一个对象(虽然为null)了呢?
多态主要用途是设定返回值类型,数组类型,参数类型的时候,可以用一种类型包涵多种子类型,方便代码重用和扩展。
数组就像杯架,变量就像杯子。引用就像遥控器,用来遥控对象。new Person[10]是一个对象,这个对象相当于一个杯架,上面有十个杯子,杯子里有十个遥控器,per[0]是第一个杯子,per[0]=stu 是让per[0]这个杯子里的遥控器,指向和stu这个遥控器相同的对象。杯子在杯架上的位置不会变,装的遥控器类型在声明的时候也已经定了,只能改变遥控器遥控的对象。
对于第三个:
Person[] person = student;这个语句中,应该是指向的同一个类型的数组(应该是Person[]这个数组吧?),那么现在,student是Student[]数组的类型呢?还是Person[]数组的类型呢?
1、如果是Student[]数组的类型,那么下面的student[0].setId(0002);这个方法是没错的,但是就不是和Person[0]指向相同数组了,
是不是这时候已经将Person[] person = student;这句的行为覆盖掉了呢?
2、如果是Person[]数组的类型,那么下面的student[0].setId(0002);这个方法是不成立的,因为编译时虽然可以通过,但是运行后会报错,如下:
希望大家能帮忙解答清晰。
这个语句是错的。
数组是个杯架,声明的时候,如果是Student[] student,那就是说,student遥控器指向的这个杯架上的杯子里面的遥控器,是遥控student类型对象的遥控器,如果是Person[] person,那么杯架上的杯子里就是遥控Person类型对象的遥控器。可是你的student这个遥控器,指向的是杯架(杯架就是数组,也是个对象),而不是Student对象,student[0]这种杯架上的杯子里的遥控器遥控的才是Student对象。遥控Person类型对象的遥控器可以指向Student类型的对象,但是指向杯架的遥控器是不兼容的。
你把Person[] person = student,这是不对的,因为person是个遥控杯架的遥控器(杯架上的杯子里装的是遥控Person的遥控器),student也是遥控杯架的,它俩杯架上的杯子装的不是一种遥控器,所以不能这样。遥控Person对象的遥控器可以指向Student对象,但是遥控杯架的遥控器类型不同不要赋值。
我们都是用遥控器(就是引用)来遥控对象的。父类的遥控器可以指向子类的对象,但是你的两种杯架Person[]和Student[]并不是继承关系,杯架上的杯子Penson[1]和Student[1]这种带下标的杯子里面的遥控器才是父子。数组是个对象,但是是个杯架,杯架的杯子里只装遥控器,也不装对象,可以装primitive类型。

评分

参与人数 1技术分 +1 收起 理由
Rancho_Gump + 1

查看全部评分

回复 使用道具 举报
王昕 发表于 2013-2-7 13:39
对于第一个:
将p = null,是p不再指向new出的“小明”这个对象了呢?还是说new出的这个“小明”也随之在内 ...

你的这个比喻,实在让我有些晕了。你说杯子里有十个遥控器,意思是说这个遥控器(引用)是在被子里(变量)里是不太对的,看下面的图(图1)就可是看出,不是这样的。你说“数组就像杯架,变量就像杯子。引用就像遥控器,用来遥控对象。”那对象比喻成什么了,遥控器遥控着什么呢?这三者没有一个是对象啊?(这里先不考虑万物皆对象这个说法啊)我觉得引用更像指针(也许不对)
对于第二个,你说"per[0]=stu 是让per[0]这个杯子里的遥控器,指向和stu这个遥控器相同的对象。”那么是不是就不指向new Person[10]中的对象了呢?
对于第三个,我觉得既然编译可以通过,这个“Person[] person = student”就是正确的,从现实生活中考虑的话,一个学生群体也是一个人群啊,那么将学生群体赋给人群,为什么就不行啊?

图1-内存.png (11.67 KB, 下载次数: 43)

内存

内存
回复 使用道具 举报
本帖最后由 王昕 于 2013-2-7 17:19 编辑

因为这是Head first Java上两三章的内容,而且书上有图。我没说杯子里有十个遥控器,一个杯子里只能有一个遥控器。
数组是对象,像杯架,它也生存在堆上,杯架不是杯子,数组里的每一个元素才是杯子,就像那种放鸡蛋的架子,有一个一个的格子。比如Student[10],这数组是个对象,生存在堆上,但是它不是十个Student对象,而是十个遥控器。new Person[10]没有建立任何Person对象,只建立了一个能放十个杯子的杯架而已。要建立Person对象必须是Person[0] = new Person();这样的才行(我只是举个无参数构造函数的例子,有参数的构造函数也行)。你图右边的对象你根本没建立起来,也不会给他分配空间,而且对象的值不会是null,引用的值才会是null,但是你这个引用是定义在方法里的,所以也没有初值,定义在类里的方法之外的引用才会自动赋初值。
回复 使用道具 举报
本帖最后由 王昕 于 2013-2-7 17:06 编辑

一个学生群体是个人群,但是你没有定义学生群是人群的子类,你只定义了学生是人的子类。学生群是人群,是这样的:
Person[] person = new Person[2];
Person[0] = new Student();
Person[1] = new Student();
Student是Person的子类没错,但是Student[]可不是Person[]的子类。Student[] student = new Student[10]这语句,右边是一个对象,只是个杯架而已,杯架上十个杯子,每个杯子一个遥控器,左边student也是个遥控器,是什么类型的遥控器?是Student[]类型的遥控器,遥控器是遥控对象的,右边对象是十个遥控器,不是十个Student对象。
你的问题主要在于,你认为new Student[10]可以建立十个Student对象,实际上没有,只建立了一个对象,这个对象就是杯架(带十个杯子十个遥控器),Student对象你还得再建。
引用是地址没错,但是对我们没用,我没没法用它做操纵对象以外的事,可以给它重新设指向的对象,但是类型得兼容。C语言里指针是个地址变量,数组名是地址常量,引用比数组名灵活一些,因为可以重新赋值,但是没有指针那么强大。
回复 使用道具 举报
本帖最后由 王昕 于 2013-2-7 17:10 编辑

你的图,把右边全删掉,把左边改成堆内存,就对了。new出来的东西就是对象,对象只能在堆上。你new出来的是左边,不过箭头还没指向任何东西,就是说你的遥控器还没配电视。等你给他赋值了就相当于设了电视给它。
回复 使用道具 举报
图形说明最简单明了

多态demo0.jpg (61.92 KB, 下载次数: 45)

多态demo0.jpg

多态demo.jpg (125.57 KB, 下载次数: 32)

多态demo.jpg

评分

参与人数 1技术分 +1 收起 理由
Rancho_Gump + 1

查看全部评分

回复 使用道具 举报
本帖最后由 朱玉玺 于 2013-2-7 19:31 编辑
  1.   Person[] person = student;
复制代码
这句是合法的而且是有效的,这里person和student的区别是,person[index]只能调用父类的方法,不能调用student特有的方法;另外你子类的name隐藏了父类的name,所以你用子类的引用调用name的时候,永远都是null。
回复 使用道具 举报
王昕 发表于 2013-2-7 13:39
对于第一个:
将p = null,是p不再指向new出的“小明”这个对象了呢?还是说new出的这个“小明”也随之在内 ...

对于说的第三点,Person[] person =student是错的这话不敢苟同
  1.   person[0] = new Student("小黑",005);//给person[0]赋Person类型的值
  2.                 student[0].setId(2);               
  3.                 System.out.println(student[0].name+student[0].getId());
复制代码
回复 使用道具 举报
本帖最后由 王昕 于 2013-2-7 19:56 编辑
朱玉玺 发表于 2013-2-7 18:58
对于说的第三点,Person[] person =student是错的这话不敢苟同


你写的代码是要说明什么?person[0]是Person类型的引用,当然可以赋Student对象给它,楼主的person是Person[]类型的引用,不是Person类型。
他的相当于Person[] person = new Student[10],这是对的?
回复 使用道具 举报
王昕 发表于 2013-2-7 19:55
你写的代码是要说明什么?person[0]是Person类型的引用,当然可以赋Student对象给它,楼主的person是Pers ...

怎么不对,如果没有person=student这句,person能用person[0]这样表示吗,并利用person[0]对student[0]指向的对象进行改变吗?
回复 使用道具 举报
朱玉玺 发表于 2013-2-7 20:13
怎么不对,如果没有person=student这句,person能用person[0]这样表示吗,并利用person[0]对student[0]指 ...

你把你的代码加在那句后面,看看输出。我看了不对啊。
回复 使用道具 举报
王昕 发表于 2013-2-7 20:25
你把你的代码加在那句后面,看看输出。我看了不对啊。

我知道,name为null是吧,这是因为Student的name隐藏了Person的name,而你在Student的name你调用的时候,永远都是null。把Student的name注释掉,你再试试。Person [] person = new Student[10],如果Person是一个接口的话,这不就是面向接口编程嘛
回复 使用道具 举报
王昕 发表于 2013-2-7 16:50
因为这是Head first Java上两三章的内容,而且书上有图。我没说杯子里有十个遥控器,一个杯子里只能有一个 ...

我不太同意你的观点,
对于你说的数组是对象,生存在堆上,我同意,但是数组只是对象的集合,是将相同类型的对象集合在一起,但是他们是一个一个的实例,而不是一个整体,即使你不给他们赋值,他们一样有初始化状态,仍然是单个的,只不过是存放在一起了。而且new Student[10]确实是在内存中创建了十个对象,而且初始化值都为null,不信你可以自己测试下面的代码:
  1. class Demo0
  2. {
  3.     public static void main(String[] args)
  4.    {
  5.        Person[] p = new Person[10];
  6.        for (int i=0;i<p.length;i++)
  7.        {
  8.            System.out.println(p[i]);       
  9.        }
  10.   }
  11. }
  12. class Person
  13. {
  14.      String name;
  15.      Person(String name)
  16.     {
  17.      this.name = name;
  18.     }
  19. }
复制代码
你还说“而且对象的值不会是null,引用的值才会是null”,这也是不对的,因为引用在一定意义上来说是指针(虽然都说java中没有指针,但是其实是存在的,只不过和c语言中的不同罢了,具体你可以自己网上查查);再没赋值之前,对象(不是基本类型)的初始化值均为null。如果不清楚,你可以上网搜搜关于每种类型再没赋值前都是怎么样的状态。只要new了,它的状态就存在了。
回复 使用道具 举报
本帖最后由 黄玉昆 于 2013-2-7 21:27 编辑
朱玉玺 发表于 2013-2-7 18:14
图形说明最简单明了

我觉得你这个第一个的赋值步骤是有点问题的,我个人觉得赋值应该这样:下图。
但是按理说第3步会在第5步之后是不存在的。但是此时就出现了一个问题,per[0]还是不是Person类型的呢?
如果是,但编译却是可以通过的,只是在运行的时候出现了我图中的那个错误:
Exception in thread "main" java.lang.ArrayStoreException: Person at DuotaiDemo.main<DuotaiDemo.java:48>,这就让人很郁闷了,难道问题仅仅是这出现的吗?
怎么会出现在第48行呢?不理解。

赋值步骤.png (160.3 KB, 下载次数: 47)

赋值步骤.png
回复 使用道具 举报
黄玉昆 发表于 2013-2-7 20:53
我不太同意你的观点,
对于你说的数组是对象,生存在堆上,我同意,但是数组只是对象的集合,是将相同类 ...

“而且对象的值不会是null,引用的值才会是nul”这句话,我觉得没错,什么是对象,对象就相当于1,2,3这样的常量,null就相当于于数字中的0,你能说2的值是0吗?对象本身就是值,用于赋给引用变量,它没有值的这个概念。你把数组理解为对象的集合,其实我倒认为数组是引用的集合(基本数据类型除外),它本身并不是把所有的对象都放在虚拟机为他开辟的内存中,而是只把这些对象的引用放在为他开辟的内存中,需要使用某个元素时,它再通过引用去调取这个元素。
回复 使用道具 举报
黄玉昆 发表于 2013-2-7 21:15
我觉得你这个第一个的赋值步骤是有点问题的,我个人觉得赋值应该这样:下图。
但是按理说第3步会在第5步之 ...

你把per[0]画在了栈内存中,其实它是在堆内存中的。试想,如果一个数组有十几万个元素,难道都这十几万个引用放在栈内存中?栈内存处理速度快,但空间有限啊
回复 使用道具 举报
本帖最后由 黄玉昆 于 2013-2-7 21:44 编辑
朱玉玺 发表于 2013-2-7 21:25
“而且对象的值不会是null,引用的值才会是nul”这句话,我觉得没错,什么是对象,对象就相当于1,2,3这样 ...

他说的是对象的值(是值)不会是null,对象在默认初始化的时候,就是null,而引用怎么会是值呢?(我不是说像这种为了让对象消亡的语句: a = null),引用字面上就是指向,指向了这个地址,而像“a = null”这种语句,只是赋值而已,是将null的值赋给a,这个操作是为了让这个指向不再存在,而a这种引用是不会有值的。我的意思是:引用是中指向(相当于“指针”),是一个“行为”,而变量才有至值,a是一个变量而已啊。
回复 使用道具 举报
朱玉玺 发表于 2013-2-7 21:34
你把per[0]画在了栈内存中,其实它是在堆内存中的。试想,如果一个数组有十几万个元素,难道都这十几万个 ...

数组与对象的内存分配方式相同。都是引用在栈,数据在堆。
回复 使用道具 举报
黄玉昆 发表于 2013-2-7 21:35
他说的是对象的值(是值)不会是null,对象在默认初始化的时候,就是null,而引用怎么会是值呢?(我不是 ...

确切的说,是引用变量的初始化值是null,对象那里用初始化啊,按我的理解,对象就是一种特殊的常量。不太懂指针~:lol
回复 使用道具 举报
123下一页
您需要登录后才可以回帖 登录 | 加入黑马