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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陪你等日出 中级黑马   /  2013-11-27 00:17  /  1403 人查看  /  8 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 陪你等日出 于 2013-11-27 12:43 编辑

接口中的方法都是抽象方法,没有方法主体,它的最主要功能是否是实现功能的扩展?
如果是的话,那么自定义的接口不就作用不大啦?
例如这两段代码:
  1. //定义一个学生抽象类,
  2. abstract class Student
  3. {
  4.         //学生都要学习
  5.         abstract void study();
  6. }
  7. class zhangsan extends Student implements Smoking
  8. {
  9.         /*
  10.         假设zhangsan是一位学生,而且他还吸烟,那么就在继承Student的同时
  11.         实现Smoking接口,吸烟就算功能的扩展了
  12.         */
  13.         //覆盖抽象方法
  14.         void study(){}
  15.         public void smoke(){}
  16. }
  17. class lisi extends Student
  18. {
  19.         //lisi是一位学生,但是不吸烟
  20.         void study(){};
  21. }
  22. //自定义一个Smoking接口
  23. interface Smoking
  24. {
  25.         void smoke();
  26. }
复制代码

  1. //定义一个学生抽象类,
  2. abstract class Student
  3. {
  4.         //学生都要学习
  5.         abstract void study();
  6. }
  7. class zhangsan extends Student
  8. {
  9.         /*
  10.         假设zhangsan是一位学生,而且他还吸烟,那么在这个类里面直接写个smoke方法
  11.         */
  12.         //覆盖抽象方法
  13.         void study(){}
  14.         public void smoke(){}
  15. }
  16. class lisi extends Student
  17. {
  18.         //lisi是一位学生,但是不吸烟
  19.         void study(){};
  20. }
复制代码

像java基础视频中老师讲的的这个例子,不自定义接口不是也一样实现了功能的扩展吗?反正都是要重新在子类里面覆盖方法的,这样自定义接口还有什么意义?

评分

参与人数 1技术分 +1 黑马币 +5 收起 理由
枫儿 + 1 + 5 神马都是浮云

查看全部评分

8 个回复

倒序浏览
楼主的想法倒是不错,但是,你有没有想过,如果王五,赵六等等很多人都吸烟,那么这些人是不是都得在自己的类里面多写一个smoke方法?当然这么做是没错,可是java的特点是什么?封装。就是把很多共性的东西封装起来,这么做的目的,一是为了代码更加简介直观,二是为了结构更加严谨,更加符合现实逻辑。

再者,如果又有些人,比如除了吸烟而且还运动,按你的意思就是这些人每个人除了在自己的类中自定义个smoke方法外,又得自定义个sport方法?
你不觉得会有很多很多重复的代码么?


在你对java中的体系大致了解一下之后会发现,java的体系很严谨,这是java封装的特性所带来的好处之一。


其实毕老师电脑机箱的例子对于理解接口是很好的。接口这个词不是瞎叫的,它确实和我们显示中的接口的功能非常的相像。只有电脑机箱在实现了usb等接口的标准之后,才会在添加usb等设备时非常方便。你可能会说,不通过usb也能通过ps/2口添加键盘鼠标,那注意:这里ps/2口也是接口。你总不能从电脑机箱里伸出几根线来接到外设上吧,再要添加设备的时候再伸出几根线来么?你觉得接口的方式好,还是从机箱里扯线的方式好?



这是我的观点。




评分

参与人数 1技术分 +1 黑马币 +5 收起 理由
枫儿 + 1 + 5 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 衣带赞 于 2013-11-27 03:47 编辑

首先,感谢楼主提出这个问题,这个问题在我刚看到这个视频时也想过,不过没有深究。现在时间充裕了,就查了下资料,弄懂这个问题了,不然估计还是不懂。

可以明确的说,如果你只有一两个类需要实现接口,那确实没有必要去实现它。但是当你有很多个类要实现某个接口的时候,它的作用就体现出来了。接口可以大大减少编程的复杂程度,具体实现我用个最简单的例子来说明。


比如你要开一个宠物店,卖各种宠物的食物,用代码来体现就是这样的:
  1. class Cat {
  2.         public void buy(){
  3.                 System.out.println("我是猫,我要买猫粮");
  4.         }
  5. }

  6. class Dog {
  7.         public void buy(){
  8.                 System.out.println("我是狗,我要买狗粮");
  9.         }
  10. }

  11. //然后下面这个类就是店主你

  12. public class Person{
  13.         public static void main(String[] args){
  14.                 Cat c = new Cat();
  15.                 c.buy();
  16.                 Dog d = new Dog();
  17.                 d.buy();
  18.         }
  19. }
复制代码
这样,你就成功的卖给了猫、狗粮食。但是你想过没有,如果不是两个动物,而是几十个,甚至上百个种类的宠物来你的店里买粮食,你需要new上百个类,来实现其中的方法,而且最糟糕的是你还必须知道是什么宠物来你的店里买粮食(也就是说你必须知道是调用哪个类中的方法,比如这个类中有buy()方法,那个中没有,你没有用接口标记,还要一行一行的去查原代码!),这个复杂程度可想而知。



接下来,我用接口来实现这个例子:
  1. interface PetBuy{         //定义一个宠物购买粮食的接口
  2.         public void buy();
  3. }

  4. class Cat implements PetBuy{
  5.         public void buy(){
  6.                 System.out.println("我是猫,我要买猫粮");
  7.         }
  8. }

  9. class Dog implements PetBuy{
  10.         public void buy(){
  11.                 System.out.println("我是狗,我要买狗粮");
  12.         }
  13. }

  14. /*这个仍然是店主你卖粮食,但是,这时你觉得请一个售货员帮你卖比较好,这样你根本就
  15. 不需要new什么各种宠物的对象,也不需要知道是什么宠物来买你的粮食*/

  16. //接下来创建一个售货员类
  17. class Salesclerk{
  18.         public void buy(PetBuy pet){
  19.                 pet.buy();      //接收一个接口,以父类调用子类中的方法
  20.         }
  21. }

  22. //这个还是店主你的类
  23. public class Person{
  24.         public static void main(String[] args){
  25.                 PetBuy cat = new Cat();  //实例化一个猫
  26.                 PetBuy dog = new Dog();  //实例化一个狗

  27.                 Salesclerk s = new Salesclerk();  //实例化一个售货员
  28.                 s.buy(cat);   //把猫给售货员
  29.                 s.buy(dog);           //把狗给售货员
  30.         }
  31. }
复制代码
这样,你就只创建了一个售货员,让售货员卖了猫粮、狗粮。如果上百个种类的宠物来你的店里买粮食,而你只需要实例化宠物的对象即可,根本就不需要知道是什么宠物来买你的粮食,直接用 s 来调用各个对象的方法,这样是不是方便管理了很多呢。

最后打个最简单比喻,你在大街上饿了,看到一个店子挂了KFC的牌子,你就可以直接进去买鸡腿、圣代。但是如果所有店子都不挂牌子,店里仍然做同样的事情,你就得一家一家门面进去问里面是不是有鸡腿、圣代卖。这就是反射了,反射的性能是很差的,而且我们要记的代码量剧增,远不如使用接口这样易于管理。

所以说接口最重要的作用就是标记,方便程序员分层管理,思路条理更加清晰。这个还是一层的例子,如果有多层,一层一层往下调用,果如不用接口,那简直是一场遭难!
比如说你这个店主开了10多家店铺,每个店铺卖不同的东西。。。如果不用接口分层管理,而是直接new每个顾客对象来调用其中方法的话,上千个类你就得都记下来。。。而且新增的类没标记你也根本也无法知晓。









评分

参与人数 1技术分 +1 黑马币 +5 收起 理由
枫儿 + 1 + 5 很给力!

查看全部评分

回复 使用道具 举报 1 0
衣带赞 发表于 2013-11-27 03:27
首先,感谢楼主提出这个问题,这个问题在我刚看到这个视频时也想过,不过没有深究。现在时间充裕了,就查了 ...

:P感谢你的耐心解答,原来接口最主要的作用是标记,但是后面百种宠物买粮食我感觉应该是用多态实现的
回复 使用道具 举报
樊志伟 发表于 2013-11-27 01:16
楼主的想法倒是不错,但是,你有没有想过,如果王五,赵六等等很多人都吸烟,那么这些人是不是都得在自己的 ...

:D感谢你的耐心解答,非常认同应该使代码体现封装特性让其结构变得更严谨,但是后面有一句我不理解“会有很多很多重复的代码”,就算是定义接口了,那些需要覆盖方法的还是得覆盖,要写的代码还是要写,代码数量不变的
回复 使用道具 举报
陪你等日出 发表于 2013-11-27 12:38
感谢你的耐心解答,原来接口最主要的作用是标记,但是后面百种宠物买粮食我感觉应该是用多态实现的 ...

你还是没理解啊,这样减少了很多代码的,用父类调用子类方法当然是多态,但是你不定义接口无法实现多态的。我这里是为了你能看的更明白才直接实例化猫、狗对象的,其实可以在把接收的参数定义成一个函数的,返回的是PetBuy中的各种子类对象。
在实际中,比如你要给用户写一个链接数据库的类,但是这么多用户,你知道他们用的是sql、mysql、oracle中的那种呢?所以你必须给每个数据库的rcud方法都写出来。而你用了接口,只需要接收一个数据库类型的参数,就可以只写一次rcud的方法。当类中相同的方法越多,使用接口越简便。
回复 使用道具 举报
衣带赞 发表于 2013-11-27 13:35
你还是没理解啊,这样减少了很多代码的,用父类调用子类方法当然是多态,但是你不定义接口无法实现多态的 ...

听你这样一说,我倒困惑了,“用了接口,只需要接收一个数据库类型的参数,就可以只写一次rcud的方法”,这个还是多态带来的便利,只是用接口实现了多态,要想实现这个便利,用抽象类也可以的啊?我说的是如果类似问题中那段代码中的接口的作用,就拿问题中的那段代码来说,再多一百个学生,有的有吸烟功能,有的没有,那么那个Smoking接口还是没有意义的吧
回复 使用道具 举报
接口最主要的作用是标记,方便分层管理。其次就是简化代码。
如果你定义继承抽象类,当然也可以简化代码,但是这又不是C++,你怎么实现多继承。如果你定义的学生类继承抽烟功能,然后来了一个运动的功能,你是把运动的方法写到抽烟的抽象类里面吗?
你仔细想想为何要定义接口,s.buy(cat); 这句话你看上去很简单,但是用c.buy(cat);和这个本质区别你没发现吗?将接收的参数换成一个函数后,这个代码就可以先于类产生,之后的所有代码都可以接着个继续用。但是用c.buy(cat);的结果是你要判断后面来的类到底是什么,那么你的代码就是if(){}。。。这样重复的把只要写一遍的代码写很多遍! 最后来了个你之前也没想到的类,就彻底不行了。
是不是很像反射,但是这个的代码比反射简单的多,如果是简单的几种方法,完全可以让后来产生的类去实现每种方法的接口,而不是去用反射,那个效率太低了。
回复 使用道具 举报
衣带赞 发表于 2013-11-27 18:40
接口最主要的作用是标记,方便分层管理。其次就是简化代码。
如果你定义继承抽象类,当然也可以简化代码, ...

非常感谢,哥们果然理解的够深刻
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马