“interface”(接口)關鍵字使抽象的概念更深入了一層。我們可將其想象為一個“純”抽象類。它允許創建者規定一個類的基本形式:方法名、自變量列表以及返回類型,但不規定方法主體。接口也包含了基本數據類型的數據成員,但它們都默認為static和final。接口只提供一種形式,並不提供實施的細節。
接口這樣描述自己:“對於實現我的所有類,看起來都應該象我現在這個樣子”。因此,采用了一個特定接口的所有代碼都知道對於那個接口可能會調用什麼方法。這便是接口的全部含義。所以我們常把接口用於建立類和類之間的一個“協議”。有些面向對象的程序設計語言采用了一個名為“protocol”(協議)的關鍵字,它做的便是與接口相同的事情。
為創建一個接口,請使用interface關鍵字,而不要用class。與類相似,我們可在interface關鍵字的前面增加一個public關鍵字(但只有接口定義於同名的一個文件內);或者將其省略,營造一種“友好的”狀態。
為了生成與一個特定的接口(或一組接口)相符的類,要使用implements(實現)關鍵字。我們要表達的意思是“接口看起來就象那個樣子,這兒是它具體的工作細節”。除這些之外,我們其他的工作都與繼承極為相似。下面是樂器例子的示意圖:

具體實現了一個接口以後,就獲得了一個普通的類,可用標准方式對其進行擴展。
可決定將一個接口中的方法聲明明確定義為“public”。但即便不明確定義,它們也會默認為public。所以在實現一個接口的時候,來自接口的方法必須定義成public。否則的話,它們會默認為“友好的”,而且會限制我們在繼承過程中對一個方法的訪問——Java編譯器不允許我們那樣做。
在Instrument例子的修改版本中,大家可明確地看出這一點。注意接口中的每個方法都嚴格地是一個聲明,它是編譯器唯一允許的。除此以外,Instrument5中沒有一個方法被聲明為public,但它們都會自動獲得public屬性。如下所示:
//: Music5.java
// Interfaces
import java.util.*;
interface Instrument5 {
// Compile-time constant:
int i = 5; // static & final
// Cannot have method definitions:
void play(); // Automatically public
String what();
void adjust();
}
class Wind5 implements Instrument5 {
public void play() {
System.out.println("Wind5.play()");
}
public String what() { return "Wind5"; }
public void adjust() {}
}
class Percussion5 implements Instrument5 {
public void play() {
System.out.println("Percussion5.play()");
}
public String what() { return "Percussion5"; }
public void adjust() {}
}
class Stringed5 implements Instrument5 {
public void play() {
System.out.println("Stringed5.play()");
}
public String what() { return "Stringed5"; }
public void adjust() {}
}
class Brass5 extends Wind5 {
public void play() {
System.out.println("Brass5.play()");
}
public void adjust() {
System.out.println("Brass5.adjust()");
}
}
class Woodwind5 extends Wind5 {
public void play() {
System.out.println("Woodwind5.play()");
}
public String what() { return "Woodwind5"; }
}
public class Music5 {
// Doesn't care about type, so new types
// added to the system still work right:
static void tune(Instrument5 i) {
// ...
i.play();
}
static void tuneAll(Instrument5[] e) {
for(int i = 0; i < e.length; i++)
tune(e[i]);
}
public static void main(String[] args) {
Instrument5[] orchestra = new Instrument5[5];
int i = 0;
// Upcasting during addition to the array:
orchestra[i++] = new Wind5();
orchestra[i++] = new Percussion5();
orchestra[i++] = new Stringed5();
orchestra[i++] = new Brass5();
orchestra[i++] = new Woodwind5();
tuneAll(orchestra);
}
} ///:~
代碼剩余的部分按相同的方式工作。我們可以自由決定上溯造型到一個名為Instrument5的“普通”類,一個名為Instrument5的“抽象”類,或者一個名為Instrument5的“接口”。所有行為都是相同的。事實上,我們在tune()方法中可以發現沒有任何證據顯示Instrument5到底是個“普通”類、“抽象”類還是一個“接口”。這是做是故意的:每種方法都使程序員能對對象的創建與使用進行不同的控制。