接口是契约而非实现,不能实例化;方法默认public abstract,字段默认public static final;default方法用于扩展接口但不可访问实现细节;optional不应出现在接口返回值中,以免语义污染。

接口不是类,不能 new InterfaceName
很多人一上来就写 new MyService(),发现编译报错 MyService is abstract; cannot be instantiated。接口是契约,不是实现——它只声明“能做什么”,不负责“怎么做”。真正干活的得是实现了它的类,比如 class RealService implements MyService。
常见错误:把接口当工具类用,试图直接调用静态方法(Java 8+ 虽支持 static 方法,但它们不属于实现契约的部分,也不参与多态)。
- 接口里所有方法默认是
public abstract,不用写修饰符,写了反而冗余 - 字段默认是
public static final,本质就是常量,别存状态或对象引用 - 想加默认行为?用
default方法,但注意:子类可以重写它,且多个接口冲突时必须显式@Override
一个类实现多个接口时,方法签名冲突怎么处理
比如 interface A { void run(); } 和 interface B { void run(); },class C implements A, B 不会报错——只要两个 run() 方法签名完全一致(返回值、参数、异常都相同),JVM 就认为是同一个契约,一个实现即可满足两者。
但一旦签名不同,比如 A.run() 返回 void,B.run() 返回 String,编译器直接拒绝:types incompatible for interface A and B。这不是运行时问题,是编译期契约矛盾。
立即学习“Java免费学习笔记(深入)”;
- 检查冲突最直接的方式:把实现类的
implements暂时删掉,看 IDE 是否对每个接口方法都标红 - Java 不允许“重载跨接口”,即不能靠返回值不同来区分两个同名方法
- 如果真需要语义相近但签名不同的能力,考虑拆成不同方法名,比如
start()和launch(),而不是硬塞进同一个名字
default 方法和抽象类的 protected 方法有什么实质区别
default 方法是接口的补丁,目标是“不破坏已有实现也能扩展接口”。但它无法访问实现类的私有成员,也不能用 this 拿到具体实例状态——它本质上还是静态绑定的,只是语法上挂在了接口里。
而抽象类的 protected 方法可以读写子类字段、调用子类 private 工具方法、甚至参与构造流程。这是继承关系带来的信任层级,接口没有这个权限。
-
default方法不能被private(Java 9+ 才支持private default,但仅限于辅助其他default方法,不可被实现类调用) - 如果逻辑需要访问实现细节(比如缓存、配置、上下文),别硬塞进
default,该用抽象类就用抽象类 - 多个
default方法互相调用没问题,但别让它变成“接口里的小框架”——那说明职责已经越界了
为什么 Optional<t></t> 不该出现在接口方法的返回值里
不是语法不允许,而是语义污染。接口定义的是“行为契约”,Optional 是一种空值策略,属于实现细节。把 Optional<user> findUser(long id)</user> 写在接口里,等于强制所有实现者必须用 Optional 包装,哪怕数据库查不到就该抛 NoResultException,或者缓存层想返回 null 做快速判空,都被卡死了。
更自然的做法是让方法签名回归业务语义:User findUser(long id),然后在 Javadoc 里写清楚“查不到返回 null”或“查不到抛 UserNotFoundException”。具体怎么表达“不存在”,由实现者按场景选——这才是接口该有的松耦合。
- 泛型擦除后,
Optional<t></t>在运行时就是Object,无法提供额外类型保障 - 客户端代码一旦依赖
Optional.isPresent(),就很难切换成异常驱动或其他空值策略 - 如果真要统一空值处理,用 AOP 或模板方法封装,别钉死在接口签名上










