Skip to content
接口也提供了其他类要实现的行为模板。

它们还在类和对象设计方面提供了重大优点,对Java的单继承面向对象编程方法提供了有益的补充。

**单继承存在的问题**
在经过深入考虑或经历复杂设计后,您可能发现,对类层次的简化是受到限制的,尤其需要在同一棵继承树的不同分支上同时使用某些行为时。

其它面向对象编程语言包含多重继承的概念,可以解决这种问题。通过多重继承,类可以继承多个超类,从而获得全部超类的行为和属性。

这种概念加大了学习和使用编程语言的难度。使用多重继承后,方法调用以及如何组织类层次的总题将复杂很多,同时容易让人迷惑,并带来了多义性。

Java接口是一组抽象行为,可以被混合到任何类中,从而给它添加超类不支持的行为。
Java接口只包含抽象方法定义和常量——即没有实例变量,也没有方法实现。

在Java类库中,期望很多完全不同的类都实现某种行为时,都将实现和使用接口。

**接口和类**
虽然类和接口的概念不同,但有很多相同的地方。与类一样,接口也是在源文件中声明的,并被编译为.class文件。在大多数情况下,在可以使用类的地方,也可以使用接口。

在本书的所有示例中,几乎都可以将类名替换为接口名。Java程序员说到“类”时,常常指 是“类或接口”。接口补充并扩展了类的功能,它们几乎被同等对待,但接口不能被实例化:new只能创建非抽象类的实例。

**实现和使用接口**
对于接口,你可以进行两项操作:在类中使用它们以及定义自己的接口。下面首先在类中使用接口:
要使用接口,可以在类定义中包含关键字implements:
public calss AnimatedSign extends Sign{
implements Runnable {
//…
}
在这个例子中,接口Runnable扩展了Sign的子类AnimatedSign的行为
由于接口只提供了抽象的方法定义,因此您必须在自己的类中使用同样的特征标来实现这些方法。

实现接口时,必须实现该接口中所有的方法,而不能有选择地实现其中的某些。通过实现接口,您在告诉用户,这个类支持整个接口。

类实现接口后,其子类将继承 这些新方法(并可以覆盖或重载它们),就像超类定义了这些方法一样。如果你的类是从实现特定接口的超类派生而来,则不必在类定义中包含关键字implements.

**实现多个接口**
与只能指定一个超类继承不同,您可以在类中包含任意数目的接口。您的类必须 实现这些接口的所有行为。要在类中包含多个接口,只需将它们的名称用逗号分开即可:
public class AnimatedSign extends sign
implements Runnable,Observer {
}
注意,实现多个接口可能将问题复杂化。如果两个接口定义了相同的方法,可以采用下面三种方式解决:

如果两个方法的特征标相同,可以在类中实现一个方法,其定义能够满足两个接口。

如果方法的参数列表不同,则是一种简单的方法重载:实现两种方法特征标,分别满足各自的接口定义。

如果方法的参数列表相同,但返回值不同,则无法创建一个能够满足两个接口的方法。别忘了,仅当参数列表(而不是返回类型)不同时,才能进行方法重载。在这种情况下,试图编译实现这两个接口的类将产生编译器错误,说明接口设计有缺陷,可能需要重新考虑设计方案。

**接口的其他用途**
几乎在任何可以使用类的地方,都可以使用接口来代替。例如,可以将变量的类型声明为接口:
lterator loop;
当变量的类型被声明为接口时,就只能存储实现了该接口的对象。可以将对象强制转换为接口,就像可以将对象强制转换为其他类那样。

**创建和扩展接口**
使用接口后,接下来需要定义自己的接口。接口很像类,声明方式几秋与类相同,也可以被组织成层次结构。然而,声明接口时必须遵循某些规则 。

**新接口**
要创建新的接口,可以这样声明它:
interface Expandable {
}
上述声明几乎与类定义相同,只是使用的是关键字interface而不是class。
接口定义内是方法和变量。

接口内的方法定义是公有和抽象的,可显式地声明这一点,如果没有包含这些限定符,它们将被自动转换为仅有和抽象的。不能在接口内将方法声明为私有或保护的。

例如,下面的Expandable接口有两个方法,其中的一个(expand())被显式声明为公有和抽象的,而另一个(contract())被隐式地声明为公胡和抽象的。
public interface Expandable {
public abstract void expand();
void contract();
}
这两个方法都是仅有和抽象的。
与类的抽象方法一样,接口中的方法也没有方法体。接口只包含方法的特征标,不涉及任何实现。
除方法外,接口还可以包含变量,但这些变量必须声明为公有、静态和final的(使之成为常量)。与方法一样,可以显式也可以隐式地声明。
接口必须是公有或包保护的,就像类一样。然而,需要注意的是,如果声明接口时没有使用限定符public,则接口不会自动将期方法转换为公有和抽象的,也不会将期常量转换为公有的。非公有接口的方法和常量也是非公有的,这些方法和常量只能被同一个包中的类和其他接口使用。
与类一样,接口也可以属性某个包。接口还可以导入其他包中的接口和类,就像类一样。

**接口中的方法**
接口中的方法,被认为是抽象的,可用于任何类,但如何为这些方法定义参数呢?您并不知道什么类将使用它们,答案在于这样一个事实,即可以在任何能够使用类名的地方使用接口名。䏍将方法参数定义为接口类型,可以创建通用参数,适用于可能使用该接口的任何类。

来看接口Trackable,它定义了方法track()和quitTracking()(不带任何参数)。可能还有一个beginTracking()方法,它接受一个参数:一个Trackable对象。

参数应为什么类型呢,实现了接口Trackable 的任何对象,而不能是特定类及其子类,解决方法是,在接口中将参数声明为Trackable:
public interface Trackabel {
public abstact Trackable beginTracking()}

然后,在类中实现该方法时,接受通用的Trackable参数,并将它强制转换为相应的对象:


**扩展接口**
与类一样,也可以将接口组织成层次结构。当接口继承另一个接口时,子接口将获得父接口中声明的所有方法定义和常量。

要扩展接口,可使用关键字extends,就像扩展类一样:


注意,也类不同的是,接口层次结构中没有像Object类那样的接口,它并没有根。接口可以独立存在,也可以继承另一个接口。
另外,不同于类层次,接口层次可以多重继承。例如,一个接口可以继承任意数量的接口(在定义的extends部分,使用逗号将它们分开),新接口将包含其所有父接口中的方法和常量。

在接口中,管理方法名冲突的规则与使用多接口的类相同。多个只有返回值不同的方法将导致编译错误。

本站总访问 — 次