Java中的接口定義了一個(gè)引用類型來創(chuàng)建抽象概念。 接口由類實(shí)現(xiàn),它是用來提供概念的實(shí)現(xiàn)。
在Java 8之前,一個(gè)接口只能包含抽象方法。 Java 8允許接口具有實(shí)現(xiàn)的靜態(tài)和默認(rèn)方法。
接口通過抽象概念定義不相關(guān)類之間的關(guān)系。例如,可以創(chuàng)建一個(gè)Person
類來表示一個(gè)人,也可以創(chuàng)建一個(gè)Dog
類來表示一只狗。
人和狗都可以走路。 這里的走路是一個(gè)抽象的概念。 狗可以走路,人也是走路。這里可以創(chuàng)建一個(gè)名為Walkable
的接口來表示走路這個(gè)概念。然后在Person
類和Dog
類中各自實(shí)現(xiàn)Walkable
概念(如:實(shí)現(xiàn)怎么走路)。 Person
類實(shí)現(xiàn)了Walkable
接口以人的方式走路(如:用兩條腿走路)。 Dog
類可以實(shí)現(xiàn)Walkable
接口以狗的方式走路(如:用四條腿走路)。
下面將使用一個(gè)例子來說明為什么需要接口。
假設(shè)Person
類有一個(gè)walk()
方法。
在相同的包下創(chuàng)建一個(gè)接口文件 - Walkable.java 并使用以下代碼 -
public interface Walkable {
void walk(); // 接口中只有一個(gè)方法
}
在相同的包下創(chuàng)建一個(gè)主類 -Main.java 并使用以下代碼 -
class Person implements Walkable {
public Person() {
}
public void walk() {
System.out.println("人走路:使用兩條腿足路.");
}
}
class Dog implements Walkable {
public Dog() {
}
public void walk() {
System.out.println("狗走路:使用四條腿足路.");
}
}
public class Main {
public static void main(String[] args) {
Walkable[] w = new Walkable[2];
w[0] = new Person();
w[1] = new Dog();
w[0].walk();
w[1].walk();
// 或者
// Person p = new Person();
// p.walk();
}
}
上面的代碼輸出結(jié)果如下 -
人走路:使用兩條腿足路.
狗走路:使用四條腿足路.
類可以在其聲明中使用關(guān)鍵字implements
實(shí)現(xiàn)一個(gè)或多個(gè)接口。通過實(shí)現(xiàn)一個(gè)接口,類保證它將為接口中聲明的所有方法提供一個(gè)實(shí)現(xiàn),或者類將自己聲明為抽象。
如果一個(gè)類實(shí)現(xiàn)了Walkable
接口,它必須提供walk()
方法的具體實(shí)現(xiàn)。
像類一樣,接口定義了一個(gè)新的引用類型。當(dāng)定義一個(gè)新的接口(例如,Walkable
)時(shí),定義一個(gè)新的參考接口類型。
以下聲明有效:
Walkable w; // w is a reference variable of type Walkable
但是不能創(chuàng)建接口類型的對(duì)象,因?yàn)榻涌谑嵌x抽象概念。 以下代碼無效,編譯會(huì)出錯(cuò):
new Walkable(); // A compile-time error
只能為類類型創(chuàng)建對(duì)象,但是可以使用一個(gè)接口類型變量來引用那些類實(shí)現(xiàn)該接口的任何對(duì)象。
如:Person
和Dog
類都實(shí)現(xiàn)了Walkable
接口,所以Walkable
類型的引用變量可以引用這兩個(gè)類的對(duì)象。如下代碼是沒有問題的:
Walkable w1 = new Person(); // OK
Walkable w2 = new Dog(); // OK
可以使用它的引用類型變量訪問接口的任何成員。 由于Walkable
接口只有一個(gè)成員,也就是walk()
方法,所以這里可以編寫如下代碼:
// Let the person walk
w1.walk();
// Let the dog walk
w2.walk();
當(dāng)調(diào)用w1
的walk()
方法時(shí),它調(diào)用Person
對(duì)象的walk()
方法,因?yàn)?code>w1指的是Person
對(duì)象。當(dāng)調(diào)用w2
的walk()
方法時(shí),它調(diào)用Dog
對(duì)象的walk()
方法,因?yàn)?code>w2指的是Dog
對(duì)象。
當(dāng)使用接口類型的引用變量調(diào)用方法時(shí),它將調(diào)用它所引用的對(duì)象的方法。
下面的代碼創(chuàng)建了一個(gè)方法來使用接口參數(shù)類型。
public class Main{
public static void main(String[] args) {
Walkable[] w = new Walkable[2];
w[0] = new Person();
w[1] = new Dog();
Walkables.letThemWalk(w);
}
}
class Walkables {
public static void letThemWalk(Walkable[] list) {
for (Walkable w : list) {
w.walk();
}
}
}
聲明接口的一般語法是 -
<modifiers> interface <interface-name> {
Constant-Declaration
Method-Declaration
Nested-Type-Declaration
}
接口聲明以修飾符列表開頭,也可以為空(不寫)。像類一樣,一個(gè)接口可以有一個(gè)公共或包級(jí)別的范圍。
關(guān)鍵字public
用于指示接口具有公共范圍。缺少范圍(不使用)修飾符表示接口具有包級(jí)別作用域。 具有包級(jí)別作用域的接口只能在其包的成員內(nèi)引用。
關(guān)鍵字interface
用于聲明接口,后面是接口的名稱。
接口的名稱必須是有效的Java標(biāo)識(shí)符。接口主體跟在其名稱后面并放在大括號(hào)內(nèi)。接口的主體可以為空。 以下是最簡(jiǎn)單的接口聲明:
package com.yiibai;
interface Updatable {
// The interface body is empty
}
像類一樣,一個(gè)接口有一個(gè)簡(jiǎn)單的名稱和一個(gè)完全限定名。關(guān)鍵字interface
后面的標(biāo)識(shí)符是其簡(jiǎn)單名稱。接口的完全限定名稱通過使用其包名稱和用點(diǎn)分隔的簡(jiǎn)單名稱組成。
在上面的示例中,Updatable
是簡(jiǎn)單的名稱,com.yiibai.Updatable
是完全限定名稱。使用接口的簡(jiǎn)單和完全限定名的規(guī)則與類的規(guī)則相同。
下面的代碼聲明一個(gè)名為ReadOnly
的接口。 它有一個(gè)公共(public
)范圍。
package com.yiibai;
public interface ReadOnly {
// The interface body is empty
}
接口聲明總是抽象的,無論是否明確聲明它為抽象。
標(biāo)記接口是沒有成員的接口。標(biāo)記接口用來標(biāo)記類具有特殊含義。
interface Shape {
}
class Circle implements Shape{
}
Shape c = new Circle();
if (c instanceof Shape) {
System.out.println("Using a Shape object");
}
Java API有許多標(biāo)記接口。如:java.lang.Cloneable
,java.io.Serializable
和java.rmi.Remote
都是標(biāo)記接口。
僅具有一個(gè)抽象方法的接口被稱為功能接口。
多態(tài)性是指對(duì)象具有多種形式的能力。多態(tài)性是對(duì)象提供其不同視圖的能力。使用接口使得我們可以創(chuàng)建一個(gè)多態(tài)對(duì)象。