在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。实际上,在日常工作中,你已经按照接口编程了,只不过如果你没有这方面的意识,那么你只是在被动的实现这一思想;表现在频繁的抱怨别人改的代码影响了你(接口没有设计到),表现在某个模块的改动引起其他模块的大规模调整(模块接口没有很好的设计)等等。下面就将Java接口做一个详细的叙述。
1、什么是接口?
Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构;二,一个类所具有的方法的特征集合,是一种逻辑上的抽象。前者叫做“Java接口”,后者叫做“接口”。
对于一个类的消费者来说,接口实际是“类浏览器”。这种工具能查找所有可用的类,总结出可对它们采取的全部操作(比如可以使用哪些成员等),并用一种清爽悦目的形式显示出来。
在Java语言规范中,一个方法的特征仅包括方法的名字,参数的数目和种类,而不包括方法的返回类型,参数的名字以及所抛出来的异常。在Java编译器检查方法的重载时,会根据这些条件判断两个方法是否是重载方法。但在Java编译器检查方法的置换时,则会进一步检查两个方法(分处超类型和子类型)的返还类型和抛出的异常是否相同。
接口技术有助于实现类之间的“松散关联”关系(loosecoupling,也称松散耦合)。“松散关联”阐述了如下两个面向对象编程中的重要原则:a.尽可能地使类独立存在,“自给自足”(tied cohesion)。b.如果类之间有依赖关系,尽可能实现松散关联(loose coupling)。
接口提供了关联以及方法调用上的可插入性,软件系统的规模越大,生命周期越长,接口使得软件系统的灵活性和可扩展性,可插入性方面得到保证。2、使用接口的两个原因
由于两方面的原因,我们使用了接口。第一个原因是规定客户程序员哪些能够使用,哪些不能。我们可在结构里构建自己的内部机制,不用担心客户程序员将其当作接口的一部分,从而*地使用或者“滥用”。
这个原因直接导致了第二个原因:我们需要接口的方法特征同方法的实现分离开。若结构在一系列程序中使用,但用户除了将消息发给 public 接口之外,不能做其他任何事情,我们就可以改变不属于public 的所有东西(如“友好的”、protected 以及private),同时不要求用户对他们的代码作任何修改。
3、接口的定义与实现
使用interface来定义一个接口。接口定义同类的定义类似,也是分为接口的声明和接口体,其中接口体由常量定义和方法定义两部分组成。定义接口的基本格式如下:
[修饰符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修饰符:可选,用于指定接口的访问权限,可选值为public。如果省略则使用默认的访问权限。
接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下,要求首字母大写。
extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用extends关键字时,父接口名为必选参数。
方法:接口中的方法只有定义而没有被实现。
例如,定义一个用于计算的接口,在该接口中定义了一个常量PI和两个方法,具体代码如下:
public interface CalInterface
{
final float PI=3.14159f;//定义用于表示圆周率的常量PI
float getArea(float r);//定义一个用于计算面积的方法getArea()
floatgetCircumference(float r);//定义一个用于计算周长的方法getCircumference()
}
注意:
与Java的类文件一样,接口文件的文件名必须与接口名相同。
实现接口
接口在定义后,就可以在类中实现该接口。在类中实现接口可以使用关键字implements,其基本格式如下:
[修饰符] class <类名> [extends 父类名] [implements 接口列表]{
}
修饰符:可选参数,用于指定类的访问权限,可选值为public、abstract和final。
类名:必选参数,用于指定类的名称,类名必须是合法的Java标识符。一般情况下,要求首字母大写。
extends 父类名:可选参数,用于指定要定义的类继承于哪个父类。当使用extends关键字时,父类名为必选参数。
implements 接口列表:可选参数,用于指定该类实现的是哪些接口。当使用implements关键字时,接口列表为必选参数。当接口列表中存在多个接口名时,各个接口名之间使用逗号分隔。
在类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。例如,编写一个名称为Cire的类,该类实现上述定义的接口Calculate,具体代码如下:
public class CireimplementsCalInterface
{
public float getArea(floatr)
{
floatarea=PI*r*r;//计算圆面积并赋值给变量area
returnarea;//返回计算后的圆面积
}
public floatgetCircumference(float r)
{
floatcircumference=2*PI*r; //计算圆周长并赋值给变量circumference
returncircumference; //返回计算后的圆周长
}
public static voidmain(String[] args)
{
Cirec = new Cire();
floatf = c.getArea(2.0f);
System.out.println(Float.toString(f));
}
}
在类的继承中,只能做单重继承,而实现接口时,一次则可以实现多个接口,每个接口间使用逗号“,”分隔。这时就可能出现常量或方法名冲突的情况,解决该问题时,如果常量冲突,则需要明确指定常量的接口,这可以通过“接口名.常量”实现。如果出现方法冲突时,则只要实现一个方法就可以了。
4、接口特性总结
interface关键字用来声明一个接口,它可以产生一个完全抽象的类,并且不提供任何具体实现。interface的特性整理如下:
(1). 接口中的方法可以有参数列表和返回类型,但不能有任何方法体。
(2). 接口中可以包含字段,但是会被隐式的声明为static和final。
(3). 接口中的字段只是被存储在该接口的静态存储区域内,而不属于该接口。
(4). 接口中的方法可以被声明为public或不声明,但结果都会按照public类型处理。
(5). 当实现一个接口时,需要将被定义的方法声明为public类型的,否则为默认访问类型,Java编译器不允许这种情况。
(6). 如果没有实现接口中所有方法,那么创建的仍然是一个接口。
(7). 扩展一个接口来生成新的接口应使用关键字extends,实现一个接口使用implements。
(8). Java接口(以及抽象类)一般用来作为一个类型的等级结构的起点。如果一个类已经有了一个主要的超类型,那么通过实现一个接口,这个类可以拥有另一个次要的超类型,这种次要的超类型叫做混合类型。
(9). 在一个等级结构中的任何一个类都可以实现一个接口,这个接口会影响到此类的所有子类,但不会影响到此类的任何父类。
5、常用API接口
在Java API的每个包中,几乎都规定了接口,以及完善这些接口需要的技术支持和处理的异常,下表中列出了这些API常用接口。
接口名 |
常量/方法 | 包名 | 功能 |
Cloneable | 无。推荐覆盖Object.clone() | java.lang | 对象拷贝 |
Comparable | int compareTo(Object o) | java.lang | 对象排序 |
Runnable | void run() | java.lang | 线程运行 |
AudioClip |
void loop() void play() void stop() |
java.applet | 音乐播放 |
ActionListener | voidactionPerformed(ActionEvent) | java.awt.event | 事件处理 |
WindowConstants |
int DISPOSE_ON_CLOSE int DO_NOTHING_ON_CLOSE int EXIT_ON_CLOSE int HIDE_ON_CLOSE |
javax.swing | 窗口控制 |