有时,需要创建一个这样的超类:该超类只定义一个为所有子类共享的一般形式,至于细节则交给每一个子类去填充.这样的类决定了子类必须实现的方法的本质,而他自己则不提供其中一个或多个方法的实现.这种情形只在超类不能为方法创建一个有意义的实现时才会发生.前面的示例中使用的TwoDShape就属于这种情况,area()的定义只是一个简单的占位符.他不计算,也不显示任何类型对象的面积.
在你创建自己的类库时会发现,一个方法在其超类的背景下的定义没有什么意义,这种情况并不少见.处理这种情况可以用了两种方式:一种方式如前例所示,就是只让他报告一条警告消息.尽管这种方式在某些情况下有用,但他并不总是很合适.你或许有必须被子类重写的方法,以求对子类而言具有某种意义.考虑一下triangle类,如果没有定义area(),那么他就是不完整的.在这种情况下,就需要一些办法来确保重写所有必须的方法,Java对于这一问题的解决方法是抽象方法(abstract method).
抽象方法是通过指定abstract类型修饰符来创建的.抽象方法没有内容,因此无须被超类实现.这样,子类就必须重写他,因为超类中定义的方法是不能使用的.声明抽象方法的基本形式如下所示:
abstract type name(parameter-list);
如你所见,没有出现方法主体.abstract修饰符只能用于实例方法,不能用于static方法或构造函数.
包含一个或多个抽象方法的类必须通过在其class声明前添加abstract修饰符来将其声明为抽象类.因为抽象类不定义完整的实现方式,所以抽象类也没有自己的对象.因此,任何使用new创建抽象类对象的尝试都会导致编译时错误.
当子类继承抽象类时,他必须实现超类中的所有抽象方法.否则,也必须将子类定义为抽象类.因此,abstract属性被继承,直到有了完整的实现.
使用抽象类可以改进TwoDShape类.因为对于未定义的二维图形而言,面积概念是没有意义的,所以上述程序的下面这个改版将TwoDShape中的area()声明为abstract,并且也把TwoDShape声明abstarct.当然,这就意味着所有派生自TwoDShape的类必须重写area().
public class test2 { // @param args public static void main(String args[]) { Triangle obj = new Triangle(1.5); System.out.println("area = "+obj.area()); } } abstract class TwoDShape { protected double width; protected double height; protected String name; TwoDShape() { width = height = 0.0; name = "none"; } abstract double area(); } class Triangle extends TwoDShape { Triangle(double x) { width = height = x; name = "Triangle"; } double area() { return width*height; } }
输出:
area = 2.25
正如程序所示,TwoDShape的所有子类必须重写area(),为了证实这一点,请创建一个不重写area()的子类.这时,将收到编译时错误.当然,还可以创建一个TwoDShape类型的对象引用,上面的程序就是这么做的.然而,这时就不能再声明TwoDShape类型的对象了.