1. 抽象基础

随着继承中子类的不断增多,子类变的越来越具体,父类变得越来越抽象,以至于不再在乎父类的实例。因此,有时将父类完全抽象化,让他没有任何实例来实现,只有子类,这种父类就叫做 抽象类
使用 abstract 修饰符来表示一个 类、方法 是抽象的。

abstract 类

  • 该类无法被实例化

image.png

  • 抽象类中一定有构造器,便于子类实例化时调用
  • 开发中,都会提供抽象类的子类,让子类对象实例化,来调用抽象类中的方法

abstract 方法

  • 只用方法声明,没有方法体

image.png

  • 抽象方法只能存在于抽象类中,实体类不能含有抽象方法。
  • 但是抽象类可以含有实体方法。
  • 实体子类必须重写抽象父类的抽象方法。

image.png

  • 只有子类重写了父类中所有的抽象方法后,此子类方可实例化。反之,一旦有没重写的抽象方法,该子类必须要是抽象类。
  • 子类要重写父类的抽象方法,也要重写父类的父类的抽象方法,以此类推,子类要重写所有父类的所有抽方法。

abstract 其他要注意的地方

  • abstract 不能 用来修饰 属性、构造器 等结构
  • abstract 不能 用来修饰 私有方法(private)、静态方法(static)、final 方法、final的类
    • 静态方法没有重写
    • final方法不能被重写
    • final类无法被继承

2. 抽象的应用

抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类
比如,在交通系统中,有卡车Truck、驳船RiverBarge、飞机Plane 等等,他们共同属于一个父类 Vehicle,交通工具都具有计算燃油、里程的功能,但是每个交通工具的计算方法又不一样,因此父类完全不能确定相关方法的方法体。这是 Vehicle 就可以声明为抽象类,对应的方法声明为抽象方法,没有方法体,让子类来自己重写对应的方法即可。
这样来看,抽象还是有些鸡肋。实际上,在开发中并不经常使用到抽象,而是用更进一步的接口来完成上述功能,这个在后续会讲到。


3. 匿名子类

现有一个抽象类 Person,形式如下:

  1. package pkg4;
  2. public abstract class Person {
  3. private String name ;
  4. private int age ;
  5. public abstract void eat();
  6. public abstract void talk();
  7. }
  1. 很显然,下述的写法是错误的,抽象类无法被实例化:
package pkg4;

public class AbstractTest {
    Person p1 = new Person() ; // ERROR
}
但是,我们可以构造一个重写了 Person 所有方法的子类的对象,不过只知道对象名而不知道子类的名称,格式如下所示:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2643809/1626597109215-bbf90749-0aea-4cd8-8e59-0ab1f1c71db0.png#clientId=uebb7c337-61d5-4&from=paste&height=283&id=u71e834b7&margin=%5Bobject%20Object%5D&name=image.png&originHeight=283&originWidth=758&originalType=binary&ratio=1&size=24651&status=done&style=none&taskId=u6f71bcfe-34a3-444f-9bff-2dc577575af&width=758)<br />匿名子类的对象创建可以说是结合了 多态性,即左边是抽象父类,但右边 new 出来的是实现了抽象方法的匿名子类。