接口和抽象类是java面向对象设计的两个基础机制。
接口是对行为的抽象,他是抽象方法的集合,利用接口可以达到API定义和实现分离的目的。接口,不能实例化;不能包含任何非常量成员,任何filed都是隐含着public static final的意义;同时,没有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。
抽象类是不能被实例化的类,用abstract关键字修饰class,其目的主要是代码重用。除了不能实例化,形式上和一般的java类并没有太大的区别,可以有一个或者多个抽象方法,也可以没有抽象方法。抽象类大多用于抽取相关java类的共用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。
java类实现interface使用implements关键字,继承abstract class 则是用extends关键字。
java类可以实现多个接口,因为接口是抽象方法的集合,所以这是声明性的,但不能通过扩展多个抽象类来重用。
在一些特定情况下,需要抽象出与具体实现,实例化无关的通用逻辑,或者纯调用关系的逻辑,但是使用传统的抽象类会陷入到单继承的窘境。常见的做法是,实现由静态方法组成的工具类(Utils),比如java.util.Collections.
为接口添加任何抽象方法,相应的所有实现了这个接口的类,也必须实现新增方法,否则会出现编译错误。对于抽象类,如果我们添加非抽象方法,其子类只会享受到能力扩展,而不是担心编译出问题。
接口的职责也不仅仅现有抽象方法的集合,其实有各种不同的实践。有一类没有任何方法的接口,叫做Marker Interface,顾名思义,它的目的就是为了声明某些东西,比如我们熟知的Cloneable 、Serializable等。
面向对象设计
面向对象的基本要素:封装、继承、多态。
封装的目的在于隐藏实务内部的实现细节,以便提高安全性和简化编程。封装提供了合理的边界,避免外部调用者接触到内部的细节。从另一个角度看,封装这种隐藏,也提供了简化的界面。
继承是代码复用的基础机制,但要注意,继承可以看作是非常紧耦合的一种关系,父类代码修改,子类行为也会变动。
多态:重写(override)、和重载(overload)、向上转型。简单说,重写是父子类中相同名字和参数的方法,不同的实现;重载是相同名字的方法,但是不同的参数,参考样例代码:
public int doSomething() {
return 0;
}
// 输入参数不同,意味着方法签名不同,重载的体现
public int doSomething(List<String> strs) {
return 0;
}
// return 类型不一样,编译不能通过
public short doSomething() {
return 0;
}
方法名称和参数一致,但是返回值不同,不是重载,编译会出错。