讨论Java编程中的一个重要概念和技术——接口。首先阐述什么是接口,它与类和抽象类的不同,以及使用接口的目的。通过实例详细讨论怎样编写接口和实现接口,怎样利用接口实现多重继承,接口本身的继承性,以及接口的具体应用实例。

概述
   类似于硬件接口设计,如计算机母板上的各种接口,Java语言中的接口,应用高度抽象概念和编程形式,以及应用时必须完善接口的要求,达到对象通过接口与外部世界的联系。

1 接口和类
   如果说类对它所代表的对象的形态和行为提供了具体的运算和操作代码,接口只是对要实现接口的所有类提出了协议(protocol)。这些协议是类和接口的通讯和对话管道,以静态常量和方法签名的形式,使不同的类之间建立起一个共享体制,这就像CPU的管脚对准其接口的插脚一样。这看起来似乎对类很宽容,实际上对类提出了管理和组织机制。对类的行为,提出了政策性的宏观控制。

public interface Plugable {
   static final String componentID = "CPU"; //可选项
   void plugin(argumentList); //可选项
}

  即接口中只规定静态常量,方法签名以及返回类型,而无具体操作代码。具体的方法行为由继承这个接口的类来实现。可以看到,一个接口有可能是只有接口名的空接口。

  接口具有可继承性。如同类一样,接口中的静态常量(如果有,只能是公共静态常量)和方法可以被实现它的类所继承。所以,接口技术为在Java中实现多重继承(multiple inheritance)提供了可能性。即一个子类可以继承多个直接超类。在Java编程中,更确切地说,应该是一个子类可以继承一个直接超类和多个接口(参见图7.4)。即:

public class SubClass extends SuperClass implements Interface1, Interface2, InterfaceN {
...
}

我们称这种多重继承为间接多重继承。因为子类仅继承了接口中对方法编写的协议规范,还必须编写完善这些方法的具体代码。

如果说子类继承超类是“is a”,即“是”的关系,类和支持类之间是“has a”,即“有”的关系,或称“组合”,那么类和接口则是“like a”,即“像是”的关系。接口表示,所有实现了我这个接口的类都具有我规定的协议,即“看起来都像我”,确切地说,“看起来都像我的签名”。因为完善这个接口的类必须按照签名和返回类型编写具体代码。当然,类知道应该调用哪些方法才可实现继承过来的接口功能。

    作一个比喻,继承好比“给予财富”,组合好比“你拥有我”,而接口则是“你中有我”。
接口技术有助于实现类之间的“松散关联”关系(loose coupling,也称松散耦合)。“松散关联”阐述了如下两个面向对象编程中的重要原则:
1. 尽可能地使类独立存在,“自给自足”(tied cohesion)。
2. 如果类之间有依赖关系,尽可能实现松散关联(loose coupling)。

接口以协议的形式建立了类之间的松散关系。体现了行为规范和行为实现的分离。使接口,这个特殊类的设计,上升到更抽象的高度。

2 接口和抽象
   接口的本质是抽象,是抽象类完全抽象化的体现。所以有些文献中称接口为“纯抽象类”。如果说在抽象类中,还允许完善了的方法和实例变量存在的话,在接口中,只允许有代表协议的方法签名和其返回类型,以及静态常量。
抽象类中,以抽象方法作为接口,成为子类实现多态的协议规范。而接口将类的全部内容升华为抽象,成为子类按照指定行为规范,遵循协议约定来实现接口功能的准则。实际上,接口对抽象类提供了行为规范和行为实现分离的绝好机会,使得改写后的抽象类更加符合“自给自足”和“松散耦合”的设计原则。如一个抽象类:

public abstract someAbstractClass {
  ...
  public abstract void someMethod();
}

分离成为一个接口和一个完善接口的类:

public interface SomeInterface {
  public abstract void someMethod();
}

以及:

public class SomeClass implements someInterface {
  ...
  public void someMethod() {...}
}

这样做的好处是:
a.使协议成为独立的接口。
b.使成为接口的协议具有更广泛的代表性和应用空间。
c.使抽象类从抽象中分离出来,使其不再包括抽象方法,因而具有创建对象的功能(注意抽象类不能够创建对象)。

3 步入接口
接口的语法格式为:

public interface InterfaceName {
  public static final varType CONSTANT_NAME = value; //可选项
  public abstract returnType methodName(argumentList); //可选项
}

其中:
interface——关键字。用来定义一个接口。
varType——任何基本变量类型。接口中的变量必须是静态常量。public、static和final关键字可以省略。一个接口可以没有静态常量。
returnType——返回类型。可以是任何变量类型或者对象,或void。
argumentList——包括参数类型和参数名。多个参数间用逗号分隔。接口中所有的方法必须是抽象方法。public和abstract关键字可以省略。一个接口可以没有方法声明。
所以接口的简化语法格式为:

public interface Interface Name {
  varType CONSTANT_NAME value; //可选项
  return Type method Name (argument List); //可选项
}

以下利用这个简化格式讨论接口技术和编程。
例1:编写一个Printable接口。

public interface Printable {
  void print();
}

这个接口规定凡是实现这个接口的类必须有print()方法,它的返回类型是void的。
例2:编写一个只有静态常量的接口。

public interface DepartmentCode {
  int ADMINI = 1;
  int FINANCE = 2;
  int MARKETING = 3;
  int SERVICES = 4;
}

这个接口只定义了静态常量。完善它的所有类必须遵循这些部门代码的规定。
例3:编写一个对所有图形组件规定位置协议的接口。

public interface Positionable {
  short X0 = 0;
  short Y0 = 0;
  short getX();
  short getY();
  void setX(short x);
  void setY(short y);
}

这个接口规定了所有图形组件的原始坐标,以及必须具有的方法协议。
例4:API的Cloneable接口。

public interface Cloneable {
}

这是Java API的空接口。它建议完善它的类应该覆盖Object.Clone()方法。

接口pk. 抽象类

    接口和抽象类虽然有相似之处,即它们都可能有抽象方法。但却有本质的不同。首先在代码编写方面,它们的语法要求存在差异。从这个角度讲,接口是纯粹抽象的类;而抽象类是一般类到接口之间的过渡。表9.1列出了接口和抽象类在语法方面的不同。
接口和抽象类的区别
象类
静态常量
一般变量
常量
静态变量
静态常量
抽象方法
方法
静态方法
抽象方法
抽象静态方法
使用关键字interface
使用关键字abstract
可以看出,Java对接口的语法有严格的限制和要求;而抽象类则是一种松散形式的抽象。它的特例可以和一般类一样,只不过标有关键字abstract而已。

接口和抽象类都不能创建对象。它们的不同主要在于应用。抽象类源于C++语言。但在C++中没有abstract关键字来定义抽象类,只是利用virtual来表示某个将要实现多态的方法,相当于名义抽象类。Java中的抽象类,还是C++中名义上的抽象类,一般用来进行和多态有关的运行和操作。

接口的主要用途可以归纳为如下几点:
事件处理规范。如API中的EventListenerActionListenerWindowListenerMouseListener等等。
识别对象规范。如API中的ComparableCloneable,等等。
输出输入规范。如编程人员自定义的PrintableFileWriterReadable,等等。
连接协议规范。如Connectable等。
特殊变量规范。如枚举变量协议接口Enumable
高层次组织和控制结构规范。如API中的Collection 接口,List接口,等等。
具有普遍意义的周边和附属功能规范。如RecycleableColorablePositionable,等等。
本章以下小节对接口在这些方面的应用作进一步讨论。表9.2列出了接口和抽象类在应用方面的比较。

接口和抽象类在应用方面的比较
应用
接口
抽象类
多重继承
一个类可以完善多个接口,即支持间接多重继承。
一个类只可以继承一个抽象类。
第三方开发和
扩展
可以在任何第三方已存在类的代码中实现接口。
为了继承抽象类,第三方类必须重写子类。
like a”与“is a
通常对边缘和附属功能提出协议性规范;具有广泛性。
通常定义对象的核心形态和行为。
同性
适用于所有实现共享签名和协议的不同应用。
适用于各种不同的实现、但都基于共同状态和行为源的应用。
自由度
只要“像我”。
必须“是我”。
可维性
相同
相同
速度
相对慢
相对快
简洁性
高。无须关键字,所有数据自动为公有静态常量。所有方法自动为抽象。
低。关键字不可省略。
可扩充性
如果在接口中添加新方法协议,必须修改所有应用它的类的代码。
如果添加完善了的新方法,无须对所有应用它的类进行修改。

常用API接口

Java API的每个包中,几乎都规定了接口,以及完善这些接口需要的技术支持和处理的异常,表3中列出了这些API常用接口。
表3 常用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
void actionPerformed(ActionEvent)
java.awt.event
事件处理
 
WindowConstants
int DISPOSE_ON_CLOSE
int DO_NOTHING_ON_CLOSE
int EXIT_ON_CLOSE
int HIDE_ON_CLOSE
javax.swing
窗口控制