一、一句话核心(必背)
JDK8 接口新增 default 默认方法:接口里可以写有方法体的实现,实现类不用强制重写;目的:接口升级扩展不破坏已有实现类代码,配合 Lambda、函数式接口平滑迭代,解决接口新增方法全实现类改代码痛点。
历史痛点:JDK7 及以前接口只有抽象方法,接口新增方法,所有实现类全部报错、必须重写,改动成本极高,default 就是解决这个问题。
二、基础语法规则
public interface TestInterface {
// 1.抽象方法(无方法体,实现类必须重写)
void abstractFunc();
// 2.默认方法 default,带实现体,实现类可选重写
default void defaultFunc() {
System.out.println("接口默认方法实现");
}
// 3.接口静态方法 static(直接接口名.方法调用,实现类不能继承)
static void staticFunc(){}
}
三条硬性规则(面试考点)
default修饰,必须有方法体;- 实现类不重写也能直接调用,按需重写;
- 一个类实现多个接口,多个接口存在同名 default → 子类必须手动重写冲突方法。
三、和 Lambda 关联:为什么 Lambda 离不开 default?
1. 函数式接口(@FunctionalInterface)限制:只能一个抽象方法,default 不计入抽象方法数量
可以在函数式接口中大量扩充默认工具方法,不破坏 Lambda 使用。
@FunctionalInterface
public interface UserHandler {
// 唯一抽象方法,用于Lambda实现
void handle(User user);
// 多个default,随便扩展,不影响Lambda
default void batchHandle(List<User> list){
list.forEach(this::handle); // 复用抽象方法
}
default void emptyHandle(){
System.out.println("空处理");
}
}
调用:
// 只用抽象方法做Lambda实现,default自带可用
UserHandler handler = u-> System.out.println(u.getName());
handler.handle(new User());
handler.batchHandle(userList); // 直接调用默认批量方法
关键:函数式接口靠 default 扩充工具能力,不用新增抽象方法,保证 Lambda 正常使用。
2.JDK 八大函数式接口大量使用 default(Predicate/Consumer/Function)
以Predicate举例,内置and()/or()/negate()默认方法,实现条件拼接,是 Lambda 流式核心:
Predicate<Integer> gt5 = n->n>5;
Predicate<Integer> lt20 = n->n<20;
// default方法and/or拼接条件
Predicate<Integer> between = gt5.and(lt20);
System.out.println(between.test(10));
没有 default,条件拼接要自己写工具类,重复造轮子。
四、四大实战运用场景(项目高频)
场景 1:老接口版本迭代升级(最核心用处)
原有接口已有上百个实现类,需要新增批量处理逻辑:
- JDK7:新增抽象方法 → 所有实现类全部报错
- JDK8:新增 default 默认方法,原有实现类一行代码不用改,自动继承方法
public interface OrderService {
// 老抽象方法,所有实现类已实现
void save(Order order);
// 新版本扩展:批量保存,default实现,老实现类无需改动
default void batchSave(List<Order> list){
list.forEach(this::save);
}
}
场景 2:Lambda 流式条件拼接(Predicate、Function 组合)
// 姓名非空 并且 年龄>18
Predicate<User> nameNotNull = u->u.getName()!=null;
Predicate<User> adult = u->u.getAge()>=18;
List<User> res = userList.stream()
.filter(nameNotNull.and(adult)) // default and
.collect(Collectors.toList());
Function:andThen()默认方法实现链式转换
Function<String,Integer> strToInt = Integer::parseInt;
Function<Integer,Boolean> bigger10 = i->i>10;
// andThen 先转数字、再判断
Function<String,Boolean> all = strToInt.andThen(bigger10);
场景 3:接口提供通用工具方法,减少工具类
把通用逻辑下沉到接口 default,实现类直接调用,不用新建 Utils 类
public interface BaseDTO {
String getId();
default boolean isEmptyId(){
return getId()==null || getId().trim().length()==0;
}
}
// DTO实现接口,直接调用
class UserDTO implements BaseDTO{
private String id;
@Override public String getId(){return id;}
}
场景 4:多接口同名 default 冲突重写
interface A{default void hello(){}}
interface B{default void hello(){}}
// 实现AB必须重写hello
class C implements A,B{
@Override
public void hello() {
// 可选指定父接口实现
A.super.hello();
}
}
五、default vs static 接口方法区分(必背)
- default:实例调用、实现类可继承可重写、配合实例 Lambda;
- static:
接口名.方法名()调用、不能被实现类继承重写、属于接口本身。
TestInterface.staticFunc(); // static调用
六、default 方法优缺点
优点
- 接口兼容扩展,新增功能不改动历史实现类,开闭原则;
- 函数式接口扩展工具方法,不破坏 Lambda;
- 通用逻辑下沉接口,减少重复工具类,避免重复造轮子;
- 支持默认实现,子类按需重写。
缺点
多接口同名 default 出现冲突,子类必须手动重写。
七、高频面试简答
- default 和抽象方法区别?抽象无实现必须重写;default 有实现、可选重写,不计入函数式接口抽象方法数量。
- 接口和抽象类都能写实现方法怎么选?多实现用接口 + default;单继承、需要成员变量用抽象类。
- default 底层原理?编译后 default 方法在接口的 class 文件有字节码实现,实现类不复制代码,运行时动态寻找接口默认实现。
八、背诵口诀
接口 default 带实现,升级扩展不用改;函数接口添工具,Lambda 不受影响来;andThen 和 and 组合,流式代码很爽快;多接口重名要重写,static 只能类名拽。
九、拓展:日常开发规范
- 通用公共逻辑优先写接口 default,减少重复代码;
- 函数式接口扩展能力一律用 default,不新增抽象方法;
- 工具性质静态逻辑写接口 static 方法。
1万+

被折叠的 条评论
为什么被折叠?



