zoukankan      html  css  js  c++  java
  • 再谈抽象类(感觉理解的更深了)

    抽象类其实一直都是一个比较困扰我的问题,自己上网看资料看书,最后总是感觉理解的不是很深,直到今天听了王克晶老师讲抽象类,感觉豁然开朗,不得不承认讲的真的太清楚了。

    首先,我们需要知道为啥要有抽象类,学了这10几天Java,我已经明显的感觉到,Java中的各种语法、结构很多都是为了简化代码的重复性,而抽象类真的大大大大大地提升了这种复用性,废话不多说,赶紧把我今天听的东西记录一下。

    下面我循序渐进地把抽象类引出来。

    首先,要先说抽象方法,抽象方法是用abstrat修饰的、没有方法体的方法,抽象方法存在的意义一定是要把它写在父类里,一定要用子类去实现,这个不仅仅是语法规定(子类不去实现父类的抽象方法会报错的,除非子类也是抽象类),更重要的抽象类的意义!!!抽象类最重要的作用就是:为所有派生类提供统一的入口,派生类的实现可以不同,但是其入口是一致的!!关于这个加粗红色的部分,后面会慢慢解释。

     1 class FlyingObject{
     2     int x;//飞行物横坐标
     3     int y;//飞行物纵坐标
     4 }
     5 class Airplane extends FlyingObject{
     6     void step() {
     7         y++;//小飞机纵向走
     8     }
     9 }
    10 class BigPlane extends FlyingObject{
    11     void step() {
    12         x++;//大飞机横向走
    13     }
    14 }
    15 class Bee extends FlyingObject{
    16     void step() {
    17         x++;//蜜蜂横向纵向都走
    18         y++;
    19     }
    20 }

    看上面这个代码,是飞机大战的几个类,第一个是飞行物,是超类,是整个天空所有飞行物的父类,后面三个一次是小飞机、大飞机和小蜜蜂,都是飞行物的子类。在这三个子类里都有step()这个方法,三个方法都是使得对象在天空的坐标发生变化的方法,但是三个方法的方法体不同,这样我们想要三个对象调用step()方法,我们就必须在主方法里这样写。

     1 public class AbstractDemo {
     2     public static void main(String[] args) {    
     3         Airplane airplane=new Airplane();
     4         airplane.step();
     5         BigPlane bigPlane=new BigPlane();
     6         bigPlane.step();
     7         Bee bee=new Bee();
     8         bee.step();
     9     }
    10 }

    要先去一个一个new三个类的对象,然后再去调用。那么问题来了,对于我们的主角英雄机而言,小飞机、大飞机和小蜜蜂都是敌人,而且这三个类都是飞行物的子类,我们为什么不可以通过向上造型创建一个FlyingObject的数组去把这些敌人都装进去呢,这样之后对敌人都可以进行统一操作了!答案当然是可以的,我们可以这样做。

    1 public class AbstractDemo {
    2     public static void main(String[] args) {    
    3         FlyingObject[] enemy=new FlyingObject[3];
    4         enemy[0]=new Airplane();
    5         enemy[1]=new BigPlane();
    6         enemy[2]=new Bee();
    7     }
    8 }

    这样一写,通过向上造型,创建了一个飞行物的数组,里面有小飞机、大飞机、小蜜蜂各种敌人,最关键的,放进数组后可以进行统一操作了。

    那么问题来了,这个时候,想让他们动起来怎么办呢?

    如果写:

    1 for(int i=0;i<enemy.length;i++)
    2  enemy[i].step();

    这样是会报错的!提示step()这个方法未定义!

    对啊!因为enemy是超类的引用数组,而step()这个方法是子类的,当然不能通过enemy[i]去调用step()方法了。

    那怎么办呢?

    这个时候,抽象类就应运而生了!!

    在超类FlyingObject里这样写:

    1 abstract class FlyingObject{
    2     int x;//飞行物横坐标
    3     int y;//飞行物纵坐标
    4     abstract void step();
    5 }

    在这个类里,加入step()方法,但是并没有方法体,因为很显然啊,我们这个时候并不想在父类里实现step()方法,step()方法对每个子类都不同啊,真正要去调用它的时候我们都是根据不同的子类去调用各自不同的step()方法啊,所以我们在超类里不能也不需要去写它的方法体,我们仅仅是想在超类里为各个子类提供一个step()方法的接口,这样就可以通过enemy[i]这个超类对象去调用step()方法了。

    因为没有方法体,所以这个方法不能属于普通成员方法,Java为我们提供了abstract关键字,将它视为抽象方法,就可以了。但是抽象方法所在的类必须为抽象类,因此在类名前也需要加入abstract关键字。

    那么问题来了,

     1 public class AbstractDemo {
     2     public static void main(String[] args) {    
     3         FlyingObject[] enemy=new FlyingObject[3];
     4         enemy[0]=new Airplane();
     5         enemy[1]=new BigPlane();
     6         enemy[2]=new Bee();
     7         for(int i=0;i<enemy.length;i++)
     8             enemy[i].step();
     9     }
    10 }

    第8行的这个enemy[i].step()如何判断它调用哪个子类的step()呢?

    这个问题问的非常好!

    很简单!当然是看enemy[i]里装着的具体是哪个对象,这是向上造型的知识。向上造型,引用能不能.出来方法,要看这个父类里有没有这个方法,.出来这个方法,具体去调用哪个方法,要看这个引用具体指向哪个对象,而我们用抽象类,都是用子类去实现父类的方法,其实也相当于把父类的抽象方法重写(覆盖)了,我们要去调用的应该是重写后的方法!

    总结一点,向上造型,能不能.出来方法是看引用的类型,.出来之后具体调用哪个类的方法要看对象!

    这样我们通过抽象类和抽象方法,就将所有的敌人都装进了enemy这个数组中,并且可以直接调用子类的方法,还可以对enemy进行统一操作!代码简化很多!复用性的魅力体现的淋漓尽致有木有!!

    再回来看开头抽象类的意义:为所有派生类提供统一的入口,派生类的实现可以不同,但是其入口是一致的!!

    现在应该就很明白了!

    这下大家就明白抽象类的作用了吧,这种知其然还知其所以然的感觉真的很好!

     

  • 相关阅读:
    HTML 布局
    HTML <div> 和<span>
    HTML 列表
    HTML 表格
    可视化反投射:坍塌尺寸的概率恢复:ICCV9论文解读
    智能座舱虚拟机系统
    深度学习白平衡(Color Constancy,AWB):ICCV2019论文解析
    面部表情视频中进行远程心率测量:ICCV2019论文解析
    高精地图中导航标识识别
    人脸标记检测:ICCV2019论文解析
  • 原文地址:https://www.cnblogs.com/haojiejiejie/p/8638320.html
Copyright © 2011-2022 走看看