Abstract Classes and Abstract Methods
Abstract classes are like regular classes with data and methods, but you cannot create instances of abstract classes using the new operator. 抽象类与普通类的区别在于能定义没有具体实现的抽象方法,而且不能被实例化。抽象类和抽象方法的定义和申明需要用abstract关键词,抽象方法没有函数体,具体语法如下图:

The abstract methods are implemented in concrete subclasses.抽象类的抽象方法在其实体子类中具体实现,也就是说实体子类需要对父类的抽象方法的函数体进行实现,例如Geometry类里面申明的getArea()抽象方法,在其子类Circle和Rectangle中实现,如下所示:
Circle类

Geometry类

Key Points
1. An abstract class cannot be instantiated using the new operator, but you can still define its constructors, which are invoked in the constructors of its subclasses. 虽然抽象类不能被实例化,但仍然能定义抽象类的构造器,它会在子类的实例化过程中被调用,前面讲过构造函数链(constructor chaining)这个概念,子函数构造器被调用时会先调用父类的构造器进行初始化,例如创建一个Circle对象,首先会先调用Geometry的构造器:
Geometry类

Circle类

测试类

结果

2. An abstract method cannot be contained in a nonabstract class. If a subclass of an abstract superclass does not implement all the abstract methods, the subclass mustbe defined as abstract. 实体类中不能含有抽象方法,如果一个实体类继承于抽象类,则必须将抽象类中申明的抽象方法全部实现。如下所示,B类没有实现其父类A中的抽象方法Method,则编译时报错。


3. A class that contains abstract methods must be abstract. However, it is possible to define an abstract class that doesn’t contain any abstract methods. 含有抽象方法的类必须为抽象类,但抽象类不一定含有抽象方法。
4. subclass can be abstract even if its superclass is concrete. 实体类的子类可以是抽象类,例如大家熟知的Object类是一个实体类,但我们定义的抽象类也是继承于该类。例如,抽象类A的父类B可以为实体类:

5. A subclass can override a method from its superclass to define it as abstract. 子类可以将父类具体的方法重写为抽象方法,尽管这种操作不常见。

6. You cannot create an instance from an abstract class using the new operator, but an abstract class can be used as a data type. 抽象类虽然不能被实例化,但能作为数据类型(引用变量类型),例如代码Geometry geo = new Circle();中,变量geo的类型为Geometry,new Circle()创建一个Circle对象将引用转换为Geometry后赋给geo变量,引用类型是否能转换,取决于对象类型和变量类型,变量类型应该为实际对象类型或其父类。
Why Abstract?
抽象类和接口是面向抽象编程或面向接口编程的核心,其目的在于通过一个抽象层将上层应用和底层实现解耦,使得系统更易于扩展和维护。我们通过形状的面积比较这个例子来看,首先我们不用抽象类来实现两个不同类型形状的面积比较。如下所示,为了比较不同几何类型的面积必须在客户端(上层应用)设计不同的比较方法。

若采用抽象类对程序进行改进,客户端程序Test和具体的实现层的类Circle、Rectangle类之间存在一个抽象层Geometry,实现了上层应用与底层实现的解耦,如下所示:

可以观察到,现在无论有多少类型的形状,只需要设计一个equals方法就行了,使得系统具有良好的可扩展性。

