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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张亚青 中级黑马   /  2013-3-17 09:39  /  2339 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 张亚青 于 2013-3-18 08:47 编辑

  1. package test;

  2. class Test4
  3. {
  4.         public static void main(String [] args )
  5.         {
  6.                 //创建一个Person类对象并直接调用其中的speak方法。
  7.                 new Person().speak();
  8.                 //创建Person对象赋值给接口Speakable类型sp,并且调用子类中的方法
  9.                 Speakable sp=new Person();
  10.                 sp.speak();
  11.                 System.out.println(sp.language);
  12.                 //sp.eat();// 【报错】这里会报错,因为sp接口中没有eat方法
  13.                 //创建Person对象赋值给父类Animal类型anim,并且调用子类中的方法
  14.                 Animal anim=new Person();
  15.                 anim.speak();
  16.                 System.out.println(sp.language);

  17.         }
  18. }


  19. //抽象类Animal
  20. abstract class Animal
  21. {
  22.         public String language="sound";
  23.         abstract void eat();
  24.         abstract void speak();
  25.         public void sleep()
  26.         {
  27.                 System.out.println("sleep");
  28.         }
  29. }
  30. //接口
  31. interface Speakable
  32. {
  33.         public static final String language="chinese";
  34.         abstract void speak();
  35. }
  36. //子类Person继承Animal的同时实现Speakable
  37. class Person extends Animal implements Speakable
  38. {
  39.         public void eat()
  40.         {
  41.                 System.out.println("Person.eat");
  42.         }
  43.         public void speak()
  44.         {
  45.                 System.out.println("Person.speak---"+super.language+"---"+Speakable.language);
  46.         }
  47.         
  48. }
复制代码
如果把Test4 的main方法中的sp.eat();去掉后运行结果如图

Person.speak---sound---chinese
Person.speak---sound---chinese
chinese
Person.speak---sound---chinese
sound



以上代码sp.eat();会报错,因为sp类型对象中不包含eat方法,这个可以理解。

【声明】
一、在多态中【<非静态>成员函数】的特点:
在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,否则失败。
在运行时期:参阅对象所属的类中是否有调用的方法。

简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

二、在多态中,【成员变量】的特点:
无论编译和运行,都参考左边(引用变量所属的类)。

三、在多态中,【静态成员函数】的特点:
无论编译和运行,都参考左边。
【问题】
1、把Person对象赋值给Speakable接口类型的sp,是不是也属于多态的一种?
2、为什么sp.speak()中可以调用父类Animal中的成员变量,sp不是已经把对象提升,这时候的sp还是Person的子类吗?

UPN[QK`O@JNH%DYYXYW((@R.jpg (9.48 KB, 下载次数: 33)

UPN[QK`O@JNH%DYYXYW((@R.jpg

点评

如果你的问题得到解决,请及时将主题改为[已解决],如果还有问题请继续追问,谢谢!  发表于 2013-3-17 10:53

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1 赞一个!

查看全部评分

7 个回复

倒序浏览
多态的体现形式就是引用型变量指向子类的对象;class Person extends Animal implements Speakable这句话的意思是 接口Speakable是父类,而抽象类Animal实现了接口,是接口的子类,Person类又继承了抽象类Animal,是抽象类Animal的子类,同时是接口的子类的子类。
所以你第二个问题的理解是错误的。
另外 我执行了你的代码 最后输出语句System.out.println(sp.language);结果不是sound 而是 sp接口父类本就有的Chinese啊

执行结果.PNG (2.84 KB, 下载次数: 32)

执行结果.PNG

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 朱盛文 于 2013-3-17 10:24 编辑

  1. package test;

  2. class Test4
  3. {
  4.         public static void main(String [] args )
  5.         {
  6.                 //创建一个Person类对象并直接调用其中的speak方法。
  7.                 new Person().speak();
  8.                 //创建Person对象赋值给接口Speakable类型sp,并且调用子类中的方法
  9.                 Speakable sp=new Person();                                //接口引用指向子类对象,满足多态前提3
  10.                 sp.speak();
  11.                 System.out.println(sp.language);
  12.                 //sp.eat();// 【报错】这里会报错,因为sp接口中没有eat方法
  13.                 //创建Person对象赋值给父类Animal类型anim,并且调用子类中的方法
  14.                 Animal anim=new Person();
  15.                 anim.speak();
  16.                 System.out.println(sp.language);                       //这里的输出结果应该是chinese,因为Person先继承Animal再实现Speakable
  17.                                                                                          //而speakable里的成员变量language被final修饰,是常量,所以是chinese
  18.         }
  19. }


  20. //抽象类Animal
  21. abstract class Animal
  22. {
  23.         public String language="sound";
  24.         abstract void eat();
  25.         abstract void speak();
  26.         public void sleep()
  27.         {
  28.                 System.out.println("sleep");
  29.         }
  30. }
  31. //接口
  32. interface Speakable
  33. {
  34.         public static final String language="chinese";
  35.         abstract void speak();
  36. }
  37. //子类Person继承Animal的同时实现Speakable
  38. class Person extends Animal implements Speakable                        //Person实现了Speakable接口,满足多态的前提1
  39. {
  40.         public void eat()
  41.         {
  42.                 System.out.println("Person.eat");
  43.         }
  44.         public void speak()                                                                // 重写了Speakable中的speak方法,满足多态前提2
  45.         {
  46.                 System.out.println("Person.speak---"+super.language+"---"+Speakable.language);
  47.         }
  48.         
  49. }
复制代码
多态的前提:
1.要有继承或者实现关系
2.要有方法的重写
3.父类(接口)引用指向子类对象

对于第一个问题,都满足多态的3个前提,所以属于多态

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 顾传文 于 2013-3-17 10:41 编辑

问题一:
把Person对象赋值给Speakable接口类型的sp也是多态的一种。
因为Java不允许继承多个父类,所以出现了接口。可以把接口看成是一种特殊的抽象类。
面向接口编程就是多态的使用,比如:Collection collection = new ArrayList();

问题二:super.language是访问继承了父类的language属性,父类Animal 中的language可以被覆盖。
Speakable.language是使用接口Speakable静态常量的值,接口中的成员变量默认是static final修饰的,不可以被覆盖。

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
1、接口和抽象类在程序的思想上没有什么太大的区别,抽象类在子类继承以后,是在父类的基础的框架上进行扩展。接口在被实现后,虽然说的是在该类的基础上实现了什么功能,但是在jvm加载执行的时候是一样的。都是先加载接口或者父类,接口的实现和抽象类的被继承只是把C++的多继承改良了,为了防止出现安全问题。所以把Person对象赋值给Speakable接口类型的sp,和把Person对象赋值给Animal anim是一样的,自然也就是多态。但是不是多态的一种,多态只有一种,就是父类引用指向子类对象。

2、你在调用的时候,语句是super.language。调用就是父类的animal的属性,他继承了父类当然可以调用,Person也实现了接口的内容,如果你把language前面的引用全部改成this.language打印结果肯定就是静态常量的值。

回复 使用道具 举报
袁术森 发表于 2013-3-17 10:14
多态的体现形式就是引用型变量指向子类的对象;class Person extends Animal implements Speakable这句话的 ...
  1.                 Animal anim=new Person();
  2.                 anim.speak();//这里本来的代码写成了sp.speak();
  3.                 System.out.println(anim.language);
复制代码
代码中有一部分错误了,已改正!!!你再试一下

另外class Person是继承了Animal类的同时又实现了Speakable,我感觉你的理解是错误的。
回复 使用道具 举报
朱盛文 发表于 2013-3-17 10:15
多态的前提:
1.要有继承或者实现关系
2.要有方法的重写

本来的代码我发错了,后来改了一次,希望你再看一下 ,
回复 使用道具 举报
张亚青 发表于 2013-3-17 10:59
代码中有一部分错误了,已改正!!!你再试一下

另外class Person是继承了Animal类的同时又实现了Speaka ...

为什么sp.speak()中可以调用父类Animal中的成员变量,sp不是已经把对象提升,这时候的sp还是Person的子类吗?
在主函数里,你共创建了new Person().speak(); Speakable sp=new Person();Animal anim=new Person();三个对象,问题中的sp是指的是  Speakable sp=new Person();中的sp,因为sp中有speak()方法,所以可以执行子类中的speak()啊。
恩对于class Person extends Animal implements Speakable这句话仔细想了想 是我理解错了,是子类Person继承Animal的同时实现Speakable,如果像我所说的那种关系的话,应该是在抽象类上实现下接口,在class person这儿只继承抽象类animal就可以了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马