抽象类可以包含抽象方法和具体方法(带实现),以及状态(数据字段)。一个类只能继承一个抽象类。当需要为继承层次结构概括某些逻辑和状态时,使用抽象类。
接口仅定义方法的签名(在Java 8之前),从Java 8开始可以包含默认实现(default)的方法和静态方法,但没有状态。一个类可以实现多个接口。使用接口定义与继承层次结构无关的行为集。
示例:
abstract class Animal { String name; public Animal(String name) { this.name = name; } abstract void makeSound(); } interface Movable { void move(); } class Dog extends Animal implements Movable { public Dog(String name) { super(name); } void makeSound() { System.out.println("Woof!"); } public void move() { System.out.println("Runs"); } }
仅包含抽象方法的抽象类与Java 8之前的接口有什么区别?它们可以互换使用吗?
回答: 不,不能总是。接口不能包含状态(实例字段),并且支持多重实现,而抽象类的继承是单一的。此外,接口的方法签名始终是public。
故事
在一个项目中,需要实现多个行为相似但属于不同层次的对象接口。开发人员选择使用抽象类,从而无法使用多重继承。最后导致了重大重构和代码重复。
故事
在一个大型REST API项目中创建了一个带字段(常量)的接口,以为这些值是可变的,就像在普通类中一样。结果试图修改这些字段导致了静默失败——值保持不变,错误长时间未被发现。
故事
在迁移到Java 8的过程中,开发人员在接口中添加了带实现的方法,但忘记考虑到部分类还通过抽象类继承同名方法。这导致了方法冲突和在解析继承时产生意外结果。