接口
由于类的继承具有单根性,每个类都只能有一个父类,如果需要给这个类增加其他的功能,就需要通过接口来实现。
比如设计一个防盗门,防盗门属于门,所以可以抽取出门这个父类,门有开和关的功能。但同时有些防盗门又有开锁和解锁的功能,这是一般简单的门不具备的,如果在父类门上加上这种功能,那么所有子类门都会继承这种锁的功能,显然不合适。所以我们把锁定义成一个接口,这个接口就具有开锁和解锁的功能,然后通过防盗门去实现这个接口,就能够解决这个问题。
接口和抽象父类类似,拥有抽象方法,但接口中只有静态常量和抽象方法,没有其他的成员。我们通常这样定义接口:
public interface MyInterface{
void foo();
//其他方法
}
其中,所有方法都是抽象方法,前面不写访问修饰符也是默认是public 和abstract的。
定义接口需要注意的是:
1.接口中只能包含抽象方法和静态常量,不能有属性变量
2.接口中所有成员都必须是public的,不写默认是public
3.接口中静态常量不写static和final也默认是static和final
4.接口中抽象方法不写abstract和public也默认有abstract和public,不能有方法体(包括大括号)
接口具有以下特性:
1.接口不可以被实例化
2.实现类必须实现接口的所有方法,除非这个类也是抽象类
3.实现类可以实现多个接口( implements),多个接口使用逗号隔开
4.接口中的变量都是静态常量(public static final),必须显式初始化
5.接口中所有方法都是抽象的
6.接口中所有成员都必须是public 的
7.接口可以被多重实现或继承,接口可以继承接口,但接口不能实现另一个接口,只能通过实现类去实现
8.接口没有构造方法
如何去实现接口:
1、编写接口(定义接口),根据需求设计抽象方法
public interface UsbInterface{
//USB接口提供服务
void service();
}
2、实现接口(通过接口的实现类去实现),实现类重写接口的所有抽象方法
public class UDisk implements UsbInterface{
public void service(){
System.out.println("连接USB口.....");
}
}
3、使用接口(实例化实现类来调用方法),可以以多态的方式使用,但不是必须使用多态
UsbInterface uDisk =new UDisk();
uDisk.service();
接口表示一种能力
接口是一种能力,体现在接口的方法上。对于实现类来说,接口就是给类去添加一种新的功能。在面向接口编程的程序设计时,只关心实现类有和能力,而不关心实现细节。关心面向接口的约定而不考虑接口的具体实现。
实现类与接口之间的关系是 has -a关系,
而子类与父类之间的关系是 is -a 关系。
比如:防盗门是一个门(is - a)
防盗门有一个锁(has - a)
一个人可以具有多项能力,同理,一个类可以实现多个接口。
接口表示一种约定
接口是一种约定,体现在接口名称和注释上。
1、有些接口只有名称
2、方法的实现方式要通过注释来约定
面向接口编程的程序设计时面向接口的约定而不考虑具体实现。像现实生活中,我们使用的电源插座,规定了两个接头间的额定电压、两个接头之间的距离、接头的形状等。后续厂商则根据约定去设计生产插座,但规定时并没有去关心到底哪个厂商来进行生产。
抽象类与接口的对比
接口 | 抽象类 | |
---|---|---|
相同点 | 不能被实例化 | 不能被实例化 |
区别 | 可多重实现或继承 | 单一继承 |
所有成员必须是公共的 | 可有私有成员 | |
所有方法必须是抽象的 | 可有非抽象方法 | |
只能包含静态常量 | 可包含变量 | |
不能有构造方法 | 有构造方法 |
相同点:
1、代表系统的抽象层
2、都不能被实例化
3、都能包含抽象方法(用于描述系统提供的服务,不必提供具体实现)
不同点:
1、在抽象类中可以为部分方法提供默认实现,而接口中只能包含抽象方法(抽象类便于复用,接口便于代码维护)
2、一个类只能继承一个直接的父类,但可以实现多个接口
3、已存在的继承树,可以方便的抽取接口,但是抽取抽象类不容易
4、使用原则不同
(1)接口做系统与外界交互的窗口(接口提供服务)
(2)接口本身一旦制定,就不允许随意修改
(3)抽象类可完成部分功能实现,还有部分功能可作为系统的扩展点
面向对象设计原则
1、多用组合,少用继承
2、针对接口编程
3、针对扩展开放,针对改变关闭(改变原有代码容易对其他关联代码带来未知bug,通常采取扩展新功能,而不去修改原有代码)