Skip to content

JDK 8 接口新特性

很长一段时间里,接口只能包含抽象方法,没有任何「身体」。这种「纯虚」的设计虽然清晰,但在实际使用中遇到了不少麻烦——

比如你想给接口添加一个新方法,所有实现类都必须修改。这在有几百个实现类的框架中简直是噩梦。

JDK 8 引入了默认方法静态方法,让接口变得更实用。

默认方法

什么是默认方法

带有 default 关键字的方法,可以有具体实现:

java
public interface Formula {
    // 普通抽象方法
    double calculate(int a);

    // 默认方法:有实现
    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}

实现类不需要重写默认方法,直接继承这个实现:

java
public class FormulaImpl implements Formula {
    @Override
    public double calculate(int a) {
        return a * 100;
    }
}

Formula f = new FormulaImpl();
f.sqrt(16);  // 直接使用默认实现:4.0

为什么需要默认方法

向后兼容。假设你有一个 Collection 接口,后来想在接口中增加一个 stream() 方法。如果不允许默认方法,所有实现类都会编译失败。

有了默认方法,可以这样:

java
public interface Collection<E> {
    // 新增抽象方法(仍需实现)
    default Stream<E> stream() {
        return stream();  // 有一个默认实现
    }
}

默认方法解决什么问题

java
// 场景:给接口新增方法

// ❌ 旧方式:所有实现类都要改
public interface A {
    void method();
    // 新增一个方法 → 100 个实现类全挂
}

// ✅ JDK 8 方式:提供默认实现
public interface A {
    void method();

    default void newMethod() {
        // 默认实现为空
    }
}
// 实现类不用改也能编译通过

多接口冲突:谁优先

当一个类实现多个接口,且这些接口有同名的默认方法时,需要处理冲突:

java
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 的实现
        A.super.hello();
        // 或选择 B 的实现
        // B.super.hello();
        // 或完全重写
        System.out.println("Hello from C");
    }
}

静态方法

接口的静态方法

JDK 8 允许在接口中定义静态方法,属于接口本身,不属于实现类:

java
public interface StringUtils {
    // 静态方法
    static boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }

    static String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }
}

// 调用
StringUtils.isEmpty("");    // true
StringUtils.reverse("hello"); // "olleh"

为什么需要接口静态方法

把工具方法放在接口里,比放在单独的工具类更方便:

java
// 以前:单独的工具类
public final class Collections {
    private Collections() { }
    public static List<String> emptyList() { ... }
}

// 现在:接口自带的工具方法
public interface List<E> {
    static <E> List<E> of(E... elements) {
        return new ArrayList<>(Arrays.asList(elements));
    }
}

静态方法 vs 默认方法

特征静态方法默认方法
归属接口本身实现类继承
调用InterfaceName.method()instance.method()
能否被重写不能
java
public interface Demo {
    static void staticMethod() {
        System.out.println("Static method");
    }

    default void defaultMethod() {
        System.out.println("Default method");
    }
}

// 静态方法调用
Demo.staticMethod();

// 默认方法调用(需要实现类)
// Demo d = new Demo() {};  // 匿名实现
// d.defaultMethod();

实战:构建可组合的接口

默认方法和静态方法让接口变得更强大,可以实现更复杂的组合设计:

java
public interface Validator<T> {
    // 抽象方法:核心验证逻辑
    boolean validate(T value);

    // 默认方法:组合验证
    default Validator<T> and(Validator<T> other) {
        return value -> validate(value) && other.validate(value);
    }

    default Validator<T> or(Validator<T> other) {
        return value -> validate(value) || other.validate(value);
    }

    // 默认方法:否定验证
    default Validator<T> negate() {
        return value -> !validate(value);
    }
}

// 实现验证器
class NonNullValidator implements Validator<Object> {
    @Override
    public boolean validate(Object value) {
        return value != null;
    }
}

class NonBlankValidator implements Validator<String> {
    @Override
    public boolean validate(String value) {
        return value != null && !value.isBlank();
    }
}

// 组合使用
Validator<String> validator = new NonBlankValidator()
    .and(new NonNullValidator<>());

validator.validate("hello");  // true
validator.validate("");      // false
validator.validate(null);     // false

总结

JDK 7 以前:接口 = 纯抽象(100% 方法签名)
JDK 8:      接口 = 抽象方法 + 默认方法 + 静态方法
特性用途示例
默认方法向后兼容、组合设计default void method() { }
静态方法接口自带的工具方法static boolean isEmpty() { }

默认方法不是「多重继承」,而是一种向后兼容的扩展机制。它让接口可以进化,而不会破坏已有实现。

基于 VitePress 构建