3.1.1 抽象类
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类,既然没有足够的信息描述一个具体的对象,因此这是一种不能实例化的类。抽象类往往用来描述我们在对具体问题进行分析、设计中得出的抽象概念。比如,如果进行一个图形编辑软件的开发,在进行具体问题分析时,存在着圆、三角形这样一些具体概念,它们是不同的,但是它们又都属于“形状”这样一个概念,即分类的标准就是具有形状,但形状是一个非常抽象概念,它并不能生成特定的对象,这个“形状类”就是一个抽象类。那么在Java语言中如何定义一个抽象类呢?
在Java语言中,用abstract关键字来修饰一个类时,这个类就是抽象类。一个抽象类只规定了其子类具有某种功能,并不规定子类中该功能是如何实现的,该功能的具体行为由子类负责实现。抽象类的抽象性是靠其中存在的抽象方法来体现的。当用abstract关键字来修饰一个方法时,该方法就是抽象方法。一个抽象方法只是声明一个方法,没有方法体(没有方法的具体实现),抽象方法的声明以分号结束。
定义一个抽象类的格式如下:
abstract class AbstractClassName{ … }
例如:
public abstract class Shape{ public abstract double area();//抽象方法 public abstract double volume();//抽象方法 }
上面的代码完成了对Shape抽象类的定义,可见定义抽象类和普通类差别不大,只是必须用abstract来修饰类名。它可以拥有一个或多个抽象方法,也可以没有定义抽象方法,但只要类中有一个方法被声明为抽象方法,则该类必须为抽象类。
当一个类被定义成abstract类时,表示一个抽象的概念,它不能用new关键字实例化对象,例如,上面定义的Shape类就是一个抽象类,只有被继承并在子类中重写其抽象方法,它才有意义。除抽象方法外,抽象类可以拥有和普通类一样的类成员。
特别提示:
不能用abstract修饰类的构造方法、静态方法和私有(private)方法。
【例3-1】 定义一个代表形状的抽象类,并派生出圆柱体类和长方体类,计算底面半径为“2”,高为“3”的圆柱体体积和长、宽、高分别为“3”,“2”,“4”的长方体体积。
//定义一个形状抽象类 abstract class Shape{ double radius,length,width,height; abstract double vol(); //求体积的抽象方法 Shape(double r,double h){ //对半径和高进行初始化的构造方法 radius = r; height = h; } Shape(double l,double w,double h){ //对长宽高进行初始化的构造方法 length = l; width = w; height = h; } } /** * 圆柱体类 */ class Circle extends Shape{ Circle(double r,double h){ super(r,h); } double vol(){ //重写父类抽象方法 return (3.1416*radius*radius*height); } } /** * 长方体类 */ class Rectangle extends Shape{ Rectangle(double l,double w,double h){ super(l,w,h); } double vol(){ //重写父类抽象方法 return (length*width*height); } } /** * 体类 */ public class AbstractClassDemo{ public static void main(String[] args) { Circle c = new Circle(2,3); Rectangle r = new Rectangle(3,2,4); System.out.println("圆柱体体积 ="+c.vol()); System.out.println("长方体体积 ="+r.vol()); } }
程序的运行结果如下:
圆柱体体积=37.6992 长方体体积=24.0
在【例3-1】中,定义了一个Shape抽象类,通过对各种具体的形状(如长方体和圆柱体等)分析,发现它们都可以求体积,而它们都是形状中的一种,从而将求体积的方法定义在形状类中,而不具体实现它。该抽象类实际上提供了一个规范,每一个继承它的子类都必须要遵守这个规范,而如何去完成这个规范是子类自己的事情。
【思考】abstract修饰的类一定有abstract修饰的方法吗?