接口不能定义构造方法,抽象类可以;接口字段默认public static final,抽象类字段修饰符任意;接口default方法冲突需类显式覆盖,抽象类final方法优先于接口default方法。

接口里不能写构造方法,抽象类可以
Java 接口本质是契约定义,不参与对象实例化流程,所以 interface 中不允许声明任何构造方法,连 private 或 protected 构造器都不行。而抽象类是类的变体,可以有构造方法(哪怕只是 protected AbstractService()),用于子类初始化时调用 super() 做预处理。
常见错误:在接口中写 public MyInterface() {},编译直接报错 Illegal modifier for the interface method; only public, abstract, default, static and private are permitted —— 这个提示里“method”是误导,实际它连构造方法都不认。
使用场景:
- 需要统一初始化逻辑(如日志上下文、资源检查),选抽象类
- 只约束行为签名、不关心对象怎么建,选接口
一个类只能继承一个抽象类,但能实现多个接口
这是 Java 单继承机制决定的硬限制。如果业务模型天然存在「多重角色」,比如一个 PaymentProcessor 既要支持 Retryable 又要符合 MetricsTrackable 还要满足 AsyncCapable,那就必须用接口组合。
立即学习“Java免费学习笔记(深入)”;
反例:把这三个能力全塞进一个抽象基类,会导致其他不需重试的支付方式也被迫继承它,破坏开闭原则。
注意点:
- 接口之间可以用
extends多重继承(如interface AdminService extends UserService, Loggable) - 抽象类实现接口时,可选择性地
default实现部分方法,减轻子类负担 - Java 8+ 允许接口含
default和static方法,但它们不能访问this或实例字段
字段默认是 public static final,抽象类字段可任意修饰
接口中所有字段自动被加上 public static final,哪怕你只写 int MAX_RETRY = 3;。这意味着你无法在运行时修改值,也不能定义实例变量。
抽象类则没有这个限制:protected String lastError;、private final ExecutorService executor; 都合法。
典型误用:
- 在接口里定义配置项如
String API_URL = System.getProperty("api.url");—— 编译期就求值,拿不到运行时环境变量 - 想用接口模拟枚举常量集,却忘了它无法封装状态或行为逻辑
更稳妥的做法是:接口只放真正不变的契约常量(如 int HTTP_OK = 200;),动态配置走抽象类的 protected 字段 + 子类构造传参。
默认方法冲突时,类实现优先于接口默认实现
当一个类同时实现两个接口,且这两个接口都提供了同签名的 default 方法,Java 编译器会报错:class X inherits unrelated defaults for method Y from types A and B。此时必须在类中显式覆盖该方法。
但如果类自己实现了该方法,或者其父类已提供具体实现,则忽略所有接口的 default 版本。
关键顺序(从高到低):
- 类自身定义的方法
- 父类中定义的方法(含抽象类里的具体方法)
- 最具体的接口默认方法(若无冲突)
这说明:不要指望靠接口默认方法做复杂逻辑复用;一旦涉及多实现,就得手动协调,否则编译不过。
容易被忽略的是:抽象类中的 final 方法会彻底屏蔽接口默认方法,哪怕签名一致也不会触发冲突提示——因为抽象类方法已锁定不可重写。









