接口的特性
(1)Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征,没有方法的实现。因此,这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为或者功能。
<span style="font-size:14px;">//Fruit接口包含水果的种植生长和收获,实现该接口类的都必须覆盖这些方法
public interface Fruit{
//种植
void plant();
//生长
void grow();
//收获
void harvest();
}</span>
(2)Java接口本身没有任何实现,只描述公共行为,不涉及表象,所以Java接口比Java抽象类更抽象化。
(3)接口把方法的特征和方法的实现分割开来。接口常常代表一个角色,它包装与该角色相关的操作和属性,而实现这个接口的类便是扮演这个角色的演员。一个角色由不同的演员来演,而不同的演员之间除了扮演一个共同的角色之外,并不要求其他共同之处;而抽象类要求是父子关系。
(4)使用接口可以实现类似于类的多重继承的功能。实现接口和实现继承的规则不同,一个类只有一个父类,但可以实现多个接口。
<span style="font-size:14px;">//Apple类实现继承
public class Apple extends Fruit{
}
//Apple类实现Fruit,Send接口
public class Apple implements Fruit,Send{
}</span>
为什么使用接口??
假设这样一种情况,两个类中的两个类似的功能,调用他们的类动态决定使用哪一种实现,为它们提供一个抽象父类,子类分别实现父类所定义的方法。问题在于,Java是一种单继承的语言,一般情况下,某个具体类可能已经有了一个超类,解决办法是给它的父类加父类,或者给它父类的父类加父类,直到移动到类等级结构的最顶端。这样一来,对一个具体类的可插入性的设计,就变成了对整个等级结构中所有类的修改。
一个等级结构中的任何一个类都可以实现一个接口,这个接口会影响到此类的所有子类,但不会影响到此类的任何超类。此类将不得不实现这个接口所规定的方法,而其子类可以从此类自动继承这些方法,当然也可以选择置换掉所有这些方法,或者其中的某些方法,这时候,这些子类具有了可插入性,并且可以用这个接口类型装载,传递实现了它的所有子类。
所以在接口中,我们关心的不是某一个具体的类,而是这个类是否实现了我们需要的接口。接口提供了关联以及方法调用上的可插入性,软件系统的灵活性、可扩展性和可插入性得到保证。
接口的定义
当定义一个接口时,实际上是在编写一个合约,该合约规定了用来描述实现接口的类能够做什么,能够充当什么样的角色。而接口中并没有功能的具体实现,具体实现由签了合约的类自己来完成,但实现时必须满足接口中的要求。
例如,可以编写一个接口aerocraft,代表飞行器的角色。在该接口中定义了飞行器起飞的方法。这样,具有飞行器功能的所有类都可以实现该接口,并具体实现接口中的方法,不同的类可以有不同的方法实现。声明接口的基本语法如下。
<访问限制修饰符> [abstract] interface <接口名>
{
//方法与成员变量的声明
}
其中访问限制符和类中的访问限制修饰符相同,可以是public或不写,含义也完全相同。如果接口定义为public类型,必须位于与其同名的Java文件中。方括号中的abstract代表可选,可写可不写,但如果不写,系统在进行编译时也会自动加上。也就是说,接口一定是抽象的。interface关键字说明定义的是接口,与class说明定义的是类是一样的。
一对花括号中包含的内容称为接口体,其中可以声明接口的方法与成员变量。因为接口声明中隐含了abstract,由于abstract代表抽象,final代表最终(很具体),它们是矛盾的,所以永远不能用final来修饰接口。
下面是两个合法的接口声明
public abstract interface Aerocraft
{}
public interface Ship
{}
接口也可以如同类一样进行继承扩展,如喷气飞行器接口可以继承飞行器接口。
interface Aerocraft{}
interface JetPlane extends Flyer{}
这样JetFlyer接口也就具有了Flyer接口的所有功能,并且其可以定义自身特有的成员变量与方法。接口与类的不同是,在Java中类不允许继承多个类,但接口可以同时从多个接口继承。在使用接口继承时,需要注意, 接口只能继承自接口,接口以外的任何类型,都不可以被接口继承。
下面是一个接口多重继承的例子
interface Aerocraft { }
interface Jet { }
interface JetPlane extends Aerocraft,Jet { }
喷气式飞机JetPlane接口同时继承了Aerocraf与Jet两个接口,两个接口之间用逗号分隔,如果有更多接口也是一样。
接口的使用
1.接口实现的基本语法:class <类名> implements <接口名列表>
接口名列表中可以有多个接口名,因为接口代表的是角色,一个类可以扮演多个角色。
//Employee接口
public interface Employee{
}
//Manager接口
public interface Manager{
}
//Person类实现了Employee与Manager接口
public class Person implements Employee,Manager{
}
Employee、Manager都是接口,分别代表普通员工与经理。Person是一个类,代表自然人,实现了Employee、Manage接口,表示人同时扮演普通员工与经理两个角色。
2.接口中方法的实现与使用
类的继承使得开发人员可以处理同类的事物,但不能处理不同类具有相同功能的事物。接口能够被很多不同的类实现,但接口中定义的方法仅仅是实现某一特定功能的规范,而并没有真实现这些功能。这些功能都需要在实现该接口的类中完成。
例如,直升机与民航客机都可以充当飞行器(Aerocraft)这个角色,但直升机与民航客机没任何继承关系,但是直升机与民航客机通过实现 Flyer 接口,使得二者都能够作为飞行器进行处理。因为类对接口的实现有上述含义,因此当一个类实现了某个接口。其应当为该接口中的所有方法提供具体实现,除非该类为抽象类。
//接口示例
package chapter05.sample5_1;
//飞行器接口
interface Aerocraft{
public void fly();
}
//民航客机接口
interface AirPlane{
//载客飞行
public void passenger();
}
//直升机接口
interface Helicopter{
//垂直飞行
public void verticaStart();
}
//阿帕奇直升机类,同时实现Aerocraft和Helicopter接口
class Apache implements Aerocraft, Helicopter{
//实现Aerocraft中的fly方法
public void fly(){
System.out.println("飞行器可飞行");
}
//实现Helicopter中的verticaStart方法
public void verticaStart(){
System.out.println("直升机可以垂直起飞");
}
}
//A380客机机类,同时实现Aerocraft和 AirPlane接口
class A380 implements Aerocraft, AirPlane{
//实现Aerocraft中的fly方法
public void fly(){
System.out.println("飞行器可飞行");
}
//实现AirPlaner中的passenger方法
public void passenger(){
System.out.println("A380可以载客625人飞行");
}
}
//主类分别实现阿帕奇直升机对象和A380对象
public class Sample5_1{
public static void main(String[] args){
//创建阿帕奇直升机对象
Apache a = new Apache();
a.fly();
a.verticaStart();
//创建A380对象
A380 a1 = new A380();
a1.fly();
a1.passenger();
}
}
上述的例子中,阿帕奇直升机实现了飞行器和直升飞机接口,空客A380实现了飞行器和民航飞机的接口。无论在阿帕奇直升机类还是在空客A380类中都必须实现接口中定义的方法,否则编译会报错。
看起来接口与抽象类很像,想了解更多接口与抽象类的区别,请关注本博客中的《接口与抽象类的区别》