第13章 抽象类和接口
13.1 引言
父类中定义了相关子类中的共同行为。接口可以用于定义类
+6的共同行为(包括非相关类)。
13.2 抽象类
抽象类不可以用于创建对象。抽象类可以包含抽象方法,这些方法将在具体的子类中实现。
在继承的层次结构中,每个新子类都使类变得越来越明确和具体。如果从一个子类追溯到父类,类就会变得更通用、更加不明确。类的设计一个确保父类包含它的子类的共同特征。有时候,一个父类设计得非常抽象,以至于它都没有任何具体的实例。这样的类称为抽象类。
方法实现取决于对象的具体类型,而不能在父类中实现,这样的方法称为抽象方法,在方法头中使用abstract修饰符表示。在父类定义抽象方法后,,父类就成为一个抽象类,在类头使用abstract修饰符表示该类为抽象类。在UML图形记号中,抽象类和抽象方法的名字用斜体表示。
抽象类和常规类很像,但是不能使用new操作符创建它的实例。抽象方法只有定义而没有实现。它的实现由子类提供。一个包含抽象方法的类必须声明为抽象类。
抽象类的构造方法定义为protected,因为它只被子类使用。创建一个具体子类的实例时,它的父类的构造方法被调用以初始化父类中定义的数据域。
13.2.2 抽象类的几点说明
下面是关于抽象类值得注意的几点:
抽象方法不能包含在非抽象类中。如果抽象父类的子类不能实现所有的抽象方法,那么子类也必须定义为抽象的。换句话说,在抽象类扩展的非抽象子类中,必须实现所有的抽象方法。还要注意到,抽象方法是非静态的。
抽象类是不能使用new操作符来初始化的。但是,仍然可以定义它的构造方法,这个构造方法在它的子类的构造方法中调用。例如,GeometricObject类的构造方法可以在Circle类和Rectangle类中调用。
包含抽象方法的类必须是抽象的。但是,可以定义一个不包含抽象方法的抽象类。在这种情况下,不能使用new操作符创建该类的实例。这种类是用来定义新子类的基类的。
即使子类的父类是具体的,这个子类也可以是抽象的。例如,Object类是具体的,但是它的子类如GeomtricObject可以是抽象的。
不能使用new操作符从一个抽象类创建一个实例,但是抽象类可以用作一种数据类型。因此,下面的语句创建一个元素是GeometricObject类型的数组是正确的:
GeometricObject[] objects = new GeometricObject[10];
然后可以创建一个GeometricObjects的实例,并将它的引用赋值给数组,如下所示:
objects[0] = new Circle();
13.3 示例学习:抽象的Number类
Number类是数值包装类、BigInteger以及BigDecimal的抽象父类。
10.7节介绍了数值包装类,10.9节介绍了BigInteger以及BigDecimal类。这写类有共同的方法byteValue()、shortValue()、intValue()、longValue()、floatValue()和doubleValue(),分别从这些类的对象返回byte、short、int、long、float、以及double值。这些共同的方法实际上在Number类中定义,该类是数值包装类、BigIntegr和BigDecimal类的父类,如图所示。
由于intValue()、longValue()、floatValue()以及doubleValue()等方法不能在Number类中给出实现,它们在Number类被定义为抽象方法。因此Number类是一个抽象类。byteValue()和shortValue()方法的实现从intValue()方法而来,如下所示:
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
Number定义为数值类的父类,这样可以定义方法来执行数值的共同操作。
13.4 示例学习:Calendar和GregorianCalendar
GregorianCalendar是抽象类Calendar的一个具体子类。
一个java.util.Date的实例表示以毫秒为精度的特定时刻。java.util.Calendar是一个抽象的基类,可以提取出详细的日历信息,例如,年、月、日、小时、分钟和秒。Calendar类的子类可以实现特定的日历系统,例如,公历(Gregorian历)、农历和犹太历。目前,java支持公历类java.util.GregorianCalendar,如图所示。Calendar类类中的add方法是抽象的,因为它的实现依赖于某个具体的日历系统。
可以使用new GregorianCalendar()利用当前时间构造一个默认的GregorianCalendar对象,可以使用new GregorianCalendar(year, month, date)利用指定的year(年)、month(月)和date(日)构造一个GregorianCalendar对象。参数month是基于0的,即0代表1月(January)。
在Calendar类中定义的get(int field)方法在Calendar类中提取日期和时间信息方面是很有用的,日期和时间域都被定义为常量,如表所示。
常量 | 说明 |
---|---|
YEAR | 日历的年份 |
MONTH | 日历的月份,0表示一月 |
DATE | 日历的天 |