Java 接口
接口(Interface)是 Java 中定义抽象行为的重要类型。本章将详细介绍接口的概念、使用以及 Java 8 后的新特性。
接口基础
什么是接口?
接口是一种抽象类型,它定义了一组方法签名,但不提供具体实现。类通过实现接口来提供具体行为。
定义接口
// 定义接口
interface Drawable {
// 抽象方法 - 没有方法体
void draw();
// 常量(默认是 public static final)
int MAX_SIZE = 100;
}
实现接口
// 实现接口
class Circle implements Drawable {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
// 必须实现抽象方法
@Override
public void draw() {
System.out.println("绘制圆形,半径:" + radius);
}
}
// 使用
Drawable drawable = new Circle(10);
drawable.draw();
多个接口实现
一个类可以实现多个接口:
interface Drawable {
void draw();
}
interface Movable {
void move();
}
// 实现多个接口
class Robot implements Drawable, Movable {
@Override
public void draw() {
System.out.println("绘制机器人");
}
@Override
public void move() {
System.out.println("机器人移动");
}
}
接口特性
接口成员
interface MyInterface {
// 抽象方法(默认 public abstract)
void method1();
// 默认方法(Java 8+)
default void method2() {
System.out.println("默认方法");
}
// 静态方法(Java 8+)
static void staticMethod() {
System.out.println("静态方法");
}
// 常量(默认 public static final)
String CONSTANT = "Hello";
}
接口继承
interface Parent {
void parentMethod();
}
interface Child extends Parent {
void childMethod();
}
// 实现 Child 需要实现所有方法
class Demo implements Child {
@Override
public void parentMethod() {}
@Override
public void childMethod() {}
}
接口多继承
接口可以继承多个接口:
interface A {
void methodA();
}
interface B {
void methodB();
}
// 多继承
interface C extends A, B {
void methodC();
}
class Implementation implements C {
@Override
public void methodA() {}
@Override
public void methodB() {}
@Override
public void methodC() {}
}
默认方法
Java 8 引入了默认方法,允许在接口中提供方法实现。
为什么需要默认方法?
- 向后兼容:在不破坏现有实现类的情况下为接口添加新方法
- 提供常用功能:为所有实现类提供默认实现
基本用法
interface Drawable {
void draw();
// 默认方法
default void printInfo() {
System.out.println("这是一个可绘制的对象");
}
}
class Circle implements Drawable {
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
// 使用
Circle circle = new Circle();
circle.draw(); // 调用实现的方法
circle.printInfo(); // 调用默认方法
默认方法冲突
当一个类实现多个接口,且这些接口有相同的默认方法时,需要解决冲突:
interface A {
default void hello() {
System.out.println("Hello from A");
}
}
interface B {
default void hello() {
System.out.println("Hello from B");
}
}
// 必须重写以解决冲突
class C implements A, B {
@Override
public void hello() {
// 可以选择调用其中一个
A.super.hello();
// 或 B.super.hello();
// 或自定义实现
System.out.println("Hello from C");
}
}
默认方法的应用
interface List<E> {
void add(E e);
E get(int index);
// 默认方法:返回列表大小
default int size() {
return 0; // 默认实现
}
// 默认方法:检查是否为空
default boolean isEmpty() {
return size() == 0;
}
// 默认方法:遍历
default void forEach(Consumer<? super E> action) {
for (int i = 0; i < size(); i++) {
action.accept(get(i));
}
}
}
静态方法
Java 8 允许在接口中定义静态方法。
interface MathUtils {
static int add(int a, int b) {
return a + b;
}
static int multiply(int a, int b) {
return a * b;
}
}
// 使用
int result = MathUtils.add(3, 5); // 8
静态方法的应用
静态方法常用于提供工厂方法或工具方法:
interface Animal {
void speak();
static Animal createDog() {
return new Dog();
}
static Animal createCat() {
return new Cat();
}
}
class Dog implements Animal {
@Override
public void speak() {
System.out.println("汪汪");
}
}
class Cat implements Animal {
@Override
public void speak() {
System.out.println("喵喵");
}
}
// 使用工厂方法
Animal dog = Animal.createDog();
dog.speak();
函数式接口
只有一个抽象方法的接口称为函数式接口,可以使用 Lambda 表达式。
@FunctionalInterface 注解
@FunctionalInterface
interface MyFunction {
void doSomething(String s);
// 可以有默认方法
default void log(String msg) {
System.out.println("Log: " + msg);
}
// 可以有静态方法
static void info() {
System.out.println("这是一个函数式接口");
}
}
// 使用 Lambda 表达式
MyFunction function = s -> System.out.println("处理: " + s);
function.doSomething("Hello");
内置函数式接口
Java 8 在 java.util.function 包中提供了大量函数式接口:
import java.util.function.*;
// 无参数,有返回值
Supplier<String> supplier = () -> "Hello";
// 有参数,无返回值
Consumer<String> consumer = s -> System.out.println(s);
// 有参数,有返回值
Function<Integer, String> function = i -> "数字: " + i;
// 返回布尔值
Predicate<Integer> predicate = i -> i > 0;
// 两个参数,无返回值
BiConsumer<String, Integer> biConsumer = (s, i) -> System.out.println(s + i);
// 两个参数,有返回值
BiFunction<Integer, Integer, String> biFunction = (a, b) -> "结果: " + (a + b);
// 基本类型特化
IntPredicate intPredicate = i -> i > 0;
LongToIntFunction longToInt = l -> (int) l;
接口与抽象类
对比
| 特性 | 接口 | 抽象类 |
|---|---|---|
| 继承 | 多实现 | 单继承 |
| 成员变量 | 只能是常量 | 可以是任意类型 |
| 方法 | 抽象方法、默认方法、静态方法 | 抽象方法、普通方法 |
| 构造方法 | 没有 | 可以有 |
| 访问修饰符 | 方法默认 public | 可以是 protected 等 |
选择
使用接口的情况:
- 需要多继承
- 定义行为规范,不关心状态
- 需要为不同类提供相同功能
使用抽象类的情况:
- 需要共享代码
- 需要非 public 成员
- 需要构造函数
// 接口 - 定义能力
interface Flyable {
void fly();
default void land() {
System.out.println("安全着陆");
}
}
interface Swimmable {
void swim();
}
// 抽象类 - 共享代码
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + "正在吃东西");
}
public abstract void makeSound();
}
// 具体类
class Duck extends Animal implements Flyable, Swimmable {
public Duck(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("嘎嘎");
}
@Override
public void fly() {
System.out.println(name + "正在飞");
}
@Override
public void swim() {
System.out.println(name + "正在游泳");
}
}
实际应用示例
1. 策略模式
interface PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付:" + amount);
}
}
class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public void pay(double amount) {
System.out.println("使用 PayPal 支付:" + amount);
}
}
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(double amount) {
paymentStrategy.pay(amount);
}
}
// 使用
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment("1234-5678"));
cart.checkout(100.00);
2. 回调模式
interface Callback {
void onSuccess(String result);
void onError(String error);
}
class AsyncTask {
public void execute(Callback callback) {
try {
// 模拟异步操作
String result = "完成";
callback.onSuccess(result);
} catch (Exception e) {
callback.onError(e.getMessage());
}
}
}
// 使用
AsyncTask task = new AsyncTask();
task.execute(new Callback() {
@Override
public void onSuccess(String result) {
System.out.println("成功:" + result);
}
@Override
public void onError(String error) {
System.out.println("失败:" + error);
}
});
// 使用 Lambda(更简洁)
task.execute(
result -> System.out.println("成功:" + result),
error -> System.out.println("失败:" + error)
);
3. 链式构建器
interface Builder<T> {
T build();
}
class User {
private String name;
private int age;
private String email;
public static class Builder implements Builder<User> {
private String name;
private int age;
private String email;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
@Override
public User build() {
User user = new User();
user.name = this.name;
user.age = this.age;
user.email = this.email;
return user;
}
}
}
// 使用
User user = new User.Builder()
.name("张三")
.age(25)
.email("[email protected]")
.build();
小结
本章我们学习了:
- 接口基础:定义和实现接口
- 接口特性:成员、继承、多继承
- 默认方法:解决向后兼容问题
- 静态方法:工具方法和工厂方法
- 函数式接口:与 Lambda 表达式配合使用
- 接口与抽象类:如何选择
- 实际应用:策略模式、回调模式、链式构建器
练习
- 定义一个 Shape 接口,包含 draw() 方法和一个默认方法
- 创建一个实现多个接口的类
- 使用函数式接口和 Lambda 表达式实现一个简单的计算器
- 实现策略模式的实际案例