抽象类与接口
抽象类和抽象方法:
声明一个抽象类的语法为:
public abstract class ClassName{
}
定义一个抽象类的主要目的是将这个类作为基类用于继承。
抽象类中包括的一个重要的东西是
抽象方法。
声明一个抽象方法的语法为:
public abstract ReturnType MethodName(arg-list);
抽象方法是用于子类在继承的时候,进行补充定义的,在父类中,抽象方法仅仅是声明而已。
注意:
* 一个含有抽象方法的类,必须定义为抽象类。
* 当一个子类继承一个抽象父类的时候,这个子类需要将抽象父类中的所有抽象方法都进行补充实现,即使这个抽象方法在这个子类中不进行使用。
* 抽象类是不能使用
new运算符来进行实例化的,抽象类是专门被设计作为父类用于继承的。
* 一个子类可以是抽象类,纵使他所继承的父类是一个非抽象类。
* 一个子类可以将其父类的方法覆盖并且声明为abstract。这样做看起来很反常,但是当父类中这个方法的实现在子类中无法使用的时候,这样做是很有用的。
在设计抽象类中的抽象方法的时候,应该尽量使这些方法在之后继承的每个子类中都有各自具体的实现,而不是空在那里,仅仅符合语法要求。
接口(Interfaces):
一个接口是一个类似于类的结构,仅仅含有常量和抽象方法。
为了使类和接口容易区分,Java使用了下列语法来声明一个接口:
modifier interface InterfaceName {
/** Constant declarations */
/** Method signatures */
}
每个接口都会编译成一个单独的bytecode文件,和普通的类是一样的。
类似于抽象类,接口也不能用
new运算符进行实例化,但是可以作为一种数据类型,或者作为强制转换的结果。
在声明了一个接口之后,在其他的类中要实现这个接口,需要使用
implements关键字。
implements关键字表明这个类继承了那个接口的所有常量和抽象方法。
抽象类 vs. 接口:
* 在接口中,所有的数据都是常量;抽象类中,可以有非常量的数据域。
* 接口中的每个方法都有还没有被实现的唯一标识;抽象类中的方法可以是具体的。
接口中,由于所有的数据域都是
public final static,所有的方法都是
public abstract。
所以这些修饰符都是可以被省略的。
e.g.
public interface T1 {
public static final int k = 1;
public abstract void p();
}
和
public interface T1 {
int k = 1;
void p();
}
是等价的。
Java只允许对于类的单继承,但是对于接口的多实现是可以的。
e.g.
public class NewClass extends BaseClass
implements Interface1, ..., InterfaceN {
...
}
e.g.
public interface NewInterface extends Interface1, ..., IntefaceN {
// constants and abstract methods
}
一个实现了接口的类必须实现在接口中定义的所有抽象方法,以及该接口的父接口中的所有抽象方法。
一个接口只能继承其他的接口,而不是其他的类。
一个类可以继承一个父类,并且可以实现众多的接口。
所有的类都享有一个共同的根源,即
Object类,但是接口是没有共同的根源的。一个接口类型的变量可以指向任何实现了这个接口的类的实例。如果一个类实现了一个接口,这个接口就像这个类的父类一样,你可以用接口作为这个类的类型变量或者是强制转换的结果。
抽象类和接口都可以用于模型化共有的特征,我们该如何决定使用接口还是抽象类呢?
一般来说,如果是一个
很强的类属关系(strong is-a relationship)描述一个父-子关系时应当使用抽象类。比如,一个员工是一个人。
而一个相对
较弱的类属关系(weak is-a relationship or is-kind-of relationship)描述一个对象拥有一些特定的属性时应当使用接口。比如所有的字符串都是可比较的。
同时,也可以使用接口来绕过Java对类单一继承的限制。