Java 接口是一组抽象方法的集合。接口用于实现抽象,其中你可以定义没有具体实现(没有方法体)的方法。接口是一种引用类型,与类相似。
除了抽象方法外,接口还可以包含常量、默认方法、静态方法和嵌套类型。只有默认方法和静态方法才有方法体。
编写接口类似于编写类。但是,类描述了对象的属性和行为,而接口包含了类所实现的行为。除非实现接口的类本身是抽象的,否则所有接口的方法都需要在类中定义。
Java 接口与类:相似性和差异性
相似性
接口与类在以下几个方面是相似的:
-
-
接口是在以
.java
扩展名命名的文件中编写的,文件名需要与接口名相同。
-
-
接口位于包中,并且相应的字节码文件必须在一个与包名匹配的目录结构中。
差异性
然而,接口与类在以下几个方面有所不同:
-
-
-
-
接口中不能包含实例字段。接口中唯一可以出现的字段必须同时声明为
static
和 final
。
-
-
在 Java 中声明接口
使用 interface
关键字声明接口。以下是一个简单的声明接口的例子:
import java.lang.*;
public interface NameOfInterface {
}
Java 接口的特性
接口具有以下特性:
-
接口隐式地是抽象的。在声明接口时不需要使用
abstract
关键字。
-
接口中的每个方法隐式地是抽象的,因此不需要
abstract
关键字。
-
在 Java 中实现接口
当一个类实现一个接口时,可以认为该类签署了一份契约,同意执行接口的具体行为。如果一个类没有执行接口的所有行为,则该类必须声明自身为抽象类。
类使用 implements
关键字实现接口。implements
关键字出现在类声明的 extends
部分之后。
实现 Java 接口的例子
public class MammalInt implements Animal {
public void eat() {
System.out.println("Mammal eats");
}
public void travel() {
System.out.println("Mammal travels");
}
public static void main(String args[]) {
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
interface Animal {
public void eat();
public void travel();
}
输出:
Mammal eats
Mammal travels
在 Java 接口中定义重写方法的规则
当重写接口中定义的方法时,有几个规则需要遵循:
-
实现方法不应声明检查异常,除非接口方法已经声明了,或者实现方法声明的是接口方法声明的子类。
-
当重写方法时,应该保持接口方法签名和相同的返回类型或子类型。
-
实现类本身可以是抽象的,如果是这样,则不需要实现接口方法。
实现 Java 接口的规则
当实现接口时,有几个规则:
-
-
-
一个接口可以扩展另一个接口,类似于一个类可以扩展另一个类的方式。
扩展 Java 接口
接口可以像类一样扩展另一个接口。使用 extends
关键字来扩展接口,子接口继承父接口的方法。
扩展 Java 接口的例子
public interface Sports {
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
public interface Football extends Sports {
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
public interface Hockey extends Sports {
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
实现多个 Java 接口
Java 类只能扩展一个父类。多重继承是不允许的。然而,接口不是类,一个接口可以扩展多个父接口。
使用一次 extends
关键字,并用逗号分隔多个父接口。
例如,如果 Hockey
接口扩展了 Sports
和 Event
,则声明如下:
public interface Hockey extends Sports, Event
实现多个 Java 接口的例子
interface Sports {
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
interface Football extends Sports {
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}
interface Hockey extends Sports {
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
interface Event {
public void organize();
}
public class HockeyDemo implements Hockey, Event {
public void setHomeTeam(String name) {
System.out.println("Home team: " + name);
}
public void setVisitingTeam(String name) {}
public void homeGoalScored() {}
public void visitingGoalScored() {}
public void endOfPeriod(int period) {}
public void overtimePeriod(int ot) {}
public static void main(String[] args) {
HockeyDemo hockeyDemo = new HockeyDemo();
hockeyDemo.setHomeTeam("India");
hockeyDemo.organize();
}
public void organize() {
System.out.println("Match organized. ");
}
}
输出:
Home team: India
Match organized.
标记 Java 接口
最常见的扩展接口的情况发生在父接口不包含任何方法的情况下。例如,在 java.awt.event
包中的 MouseListener
接口扩展了 java.util.EventListener
,定义如下:
package java.util;
public interface EventListener {}
一个没有方法的接口被称为标记接口。标记接口的设计目的有两个基本方面:
-
创建一个共同的父接口 —— 例如,
EventListener
接口被 Java API 中的几十个其他接口所扩展,你可以使用标记接口来创建一组接口之间的共同父接口。例如,当一个接口扩展 EventListener
时,JVM 知道这个特定接口将用于事件委托场景。
-
向类添加一个数据类型 —— 这就是术语“标记”来源于此的情况。实现标记接口的类不需要定义任何方法(因为接口没有任何方法),但通过多态性,类成为接口类型。