接口 (Interface)
一、接口的基本概念
1. 定义与性质
-
定义 :接口是 Java 中的一种引用数据类型 ,用于定义一组行为规范 或规则。
-
关键字 :
interface -
格式:
java
public interface 接口名 { // 接口内容 } -
核心性质:
-
接口不能被实例化 (不能
new接口)。 -
接口主要用来定义类必须遵循的规则(方法声明)。
-
它是一种纯粹的 "是什么能做什么" 的契约。
-
2. 实现关系
-
关键字 :
implements -
格式:
java
public class 类名 implements 接口名 { // 类的内容 }实现了接口的类称为该接口的 "实现类"。
3. 实现类的规则
当一个普通类实现一个接口时:
-
必须重写接口中的所有抽象方法(推荐,成为具体类)
-
或者将自己声明为抽象类(如果不重写所有抽象方法)
java
// 定义接口
public interface Animal {
void eat(); // 抽象方法(默认 public abstract)
void sleep();
}
// 实现方式1:重写所有方法
public class Dog implements Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗在睡觉");
}
}
// 实现方式2:成为抽象类
public abstract class Cat implements Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 没有重写 sleep() 方法,所以 Cat 必须是抽象类
}
二、接口与类的关系
1. 实现关系的特点
-
单实现:一个类实现一个接口
-
多实现 :一个类可以实现多个接口
-
继承与实现共存:一个类可以继承一个父类的同时实现多个接口
java
// 多实现示例
public interface Swimmable {
void swim();
}
public interface Flyable {
void fly();
}
// 一个类实现多个接口
public class Duck implements Swimmable, Flyable {
@Override
public void swim() {
System.out.println("鸭子在游泳");
}
@Override
public void fly() {
System.out.println("鸭子在飞");
}
}
// 继承与实现共存
public class Animal {
public void breathe() {
System.out.println("呼吸");
}
}
public class SuperDuck extends Animal implements Swimmable, Flyable {
@Override
public void swim() {
System.out.println("超级鸭游泳");
}
@Override
public void fly() {
System.out.println("超级鸭飞翔");
}
}
2. 类、接口之间的各种关系总结
| 关系类型 | 关键字 | 特点 |
|---|---|---|
| 类与类 | extends |
单继承,不支持多继承,但支持多层继承 |
| 类与接口 | implements |
多实现,一个类可以实现多个接口 |
| 接口与接口 | extends |
多继承,一个接口可以继承多个接口 |
接口多继承示例:
java
public interface A {
void methodA();
}
public interface B {
void methodB();
}
// 接口C继承接口A和B
public interface C extends A, B {
void methodC();
}
// 实现类需要实现所有抽象方法
public class MyClass implements C {
@Override
public void methodA() { /* 实现 */ }
@Override
public void methodB() { /* 实现 */ }
@Override
public void methodC() { /* 实现 */ }
}
三、接口的成员特点(JDK 7 及以前)
在 JDK 8 之前,接口中只能包含以下内容:
| 成员类型 | 特点 | 默认修饰符 | 示例 |
|---|---|---|---|
| 成员变量 | 常量,必须初始化 | public static final |
int MAX_VALUE = 100; |
| 构造方法 | 没有 | - | - |
| 成员方法 | 抽象方法 | public abstract |
void doSomething(); |
示例:
java
public interface MyInterface {
// 常量(public static final 可以省略)
public static final int MAX = 100;
String NAME = "接口"; // 等价于 public static final String NAME = "接口";
// 抽象方法(public abstract 可以省略)
public abstract void show();
void doWork(); // 等价于 public abstract void doWork();
// 不能有构造方法
// public MyInterface() {} // 编译错误!
// 不能有普通方法
// public void normalMethod() { } // 编译错误!
}
四、JDK 8 及以后接口的新特性
1. 默认方法(Default Method)
-
目的 :解决接口升级问题。当接口需要添加新方法时,如果直接添加抽象方法,会导致所有实现类都要修改。默认方法提供了默认实现,不会破坏现有代码。
-
格式:
java
public default 返回值类型 方法名(参数列表) { // 方法体 } -
特点:
-
使用
default关键字修饰 -
不是抽象方法,所以不强制重写
-
public可以省略,但default不能省略 -
可以被实现类直接继承使用,也可以被重写
-
java
public interface USB {
// 抽象方法
void connect();
// 默认方法(解决接口升级问题)
default void transferData() {
System.out.println("默认的数据传输方式");
}
// JDK 8 也可以有静态方法
static void showVersion() {
System.out.println("USB 3.0");
}
}
public class Mouse implements USB {
@Override
public void connect() {
System.out.println("鼠标已连接");
}
// 可以不重写 transferData(),使用默认实现
}
public class Keyboard implements USB {
@Override
public void connect() {
System.out.println("键盘已连接");
}
// 也可以重写默认方法
@Override
public void transferData() {
System.out.println("键盘使用特殊方式传输数据");
}
}
2. 默认方法的冲突规则
当实现类实现了多个接口,且这些接口有同名的默认方法时:
java
public interface A {
default void show() {
System.out.println("A的show方法");
}
}
public interface B {
default void show() {
System.out.println("B的show方法");
}
}
// 编译错误:必须重写show方法解决冲突
public class C implements A, B {
@Override
public void show() {
// 可以选择调用某一个接口的默认方法
A.super.show(); // 调用A接口的show方法
// 或者提供自己的实现
System.out.println("C重写的show方法");
}
}
3. 静态方法(JDK 8)
-
格式 :
public static 返回值类型 方法名(参数列表) { } -
特点:
-
属于接口本身,通过
接口名.方法名()调用 -
不能被子类继承或重写
-
常用于工具方法
-
java
public interface MathUtils {
static int max(int a, int b) {
return a > b ? a : b;
}
}
// 使用
int result = MathUtils.max(10, 20);
4. 私有方法(JDK 9)
-
目的 :为默认方法或静态方法提供内部辅助方法,抽取公共代码,提高代码复用性。
-
格式:
java
// 普通私有方法:为默认方法服务 private 返回值类型 方法名(参数列表) { } // 静态私有方法:为静态方法服务 private static 返回值类型 方法名(参数列表) { } -
特点:只能在接口内部使用
java
public interface DataProcessor {
default void processData(String data) {
String cleaned = cleanData(data); // 调用私有方法
System.out.println("处理数据: " + cleaned);
}
static void validate(String data) {
if (isValid(data)) { // 调用私有静态方法
System.out.println("数据有效");
}
}
// 私有方法(JDK 9+)
private String cleanData(String data) {
return data.trim().toLowerCase();
}
// 私有静态方法(JDK 9+)
private static boolean isValid(String data) {
return data != null && !data.isEmpty();
}
}
五、接口总结对比
| 版本 | 成员变量 | 构造方法 | 成员方法 |
|---|---|---|---|
| JDK 7 及以前 | 只能是常量 public static final |
没有 | 只能是抽象方法 public abstract |
| JDK 8 | 同上 | 同上 | 抽象方法、默认方法(default)、静态方法(static) |
| JDK 9 | 同上 | 同上 | 增加了私有方法(private)、私有静态方法 |
六、适配器设计模式
1. 问题场景
当一个接口中有大量抽象方法,但实现类只需要使用其中一部分时,如果直接实现接口,就需要重写所有方法(即使大部分方法体为空)。这会导致代码冗余。
2. 解决方案:适配器模式
-
核心思想 :创建一个中间适配器类 ,对接口中的所有方法进行空实现。
-
实现步骤:
-
定义中间类
XXXAdapter,用abstract修饰,防止被实例化。 -
空实现接口中的所有抽象方法(方法体为空
{})。 -
真正的实现类继承适配器类,只重写需要的方法。
-
3. 完整示例
java
// 1. 定义接口(有很多方法)
public interface WindowListener {
void windowOpened();
void windowClosing();
void windowClosed();
void windowIconified();
void windowDeiconified();
void windowActivated();
void windowDeactivated();
}
// 2. 创建适配器类(中间类)
public abstract class WindowAdapter implements WindowListener {
// 空实现所有方法
@Override
public void windowOpened() {}
@Override
public void windowClosing() {}
@Override
public void windowClosed() {}
@Override
public void windowIconified() {}
@Override
public void windowDeiconified() {}
@Override
public void windowActivated() {}
@Override
public void windowDeactivated() {}
}
// 3. 真正的实现类
public class MyWindow extends WindowAdapter {
// 只需要重写关心的方法
@Override
public void windowClosing() {
System.out.println("窗口正在关闭,执行清理操作...");
System.exit(0);
}
@Override
public void windowOpened() {
System.out.println("窗口已打开");
}
// 其他方法使用适配器中的空实现,无需重写
}
// 4. 使用
public class Test {
public static void main(String[] args) {
MyWindow window = new MyWindow();
// 只会执行重写的方法
window.windowOpened(); // 输出:窗口已打开
window.windowClosing(); // 输出:窗口正在关闭,执行清理操作...
window.windowClosed(); // 无输出(使用空实现)
}
}
七、接口的应用场景
-
定义标准/规范:如 JDBC 接口、Servlet 接口
-
解耦:面向接口编程,降低模块间耦合度
-
扩展性:通过实现不同接口,为类添加不同能力
-
替代多继承:Java 不支持类的多继承,但支持接口的多实现
设计原则 :面向接口编程,而不是面向实现编程。这样可以提高代码的灵活性、可扩展性和可维护性。