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() { } |
默认方法不是「多重继承」,而是一种向后兼容的扩展机制。它让接口可以进化,而不会破坏已有实现。
