




接口不能定义构造方法,抽象类可以;接口字段默认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,那就必须用接口组合。
反例:把这三个能力全塞进一个抽象基类,会导致其他不需重试的支付方式也被迫继承它,破坏开闭原则。
注意点:
extends 多重继承(如 interface AdminService extends UserService, Loggable)default 实现部分方法,减轻子类负担default 和 static 方法,但它们不能访问 this 或实例字段接口中所有字段自动被加上 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 方法会彻底屏蔽接口默认方法,哪怕签名一致也不会触发冲突提示——因为抽象类方法已锁定不可重写。