在 Java 中,抽象类 和接口 都是用来实现类与类之间的共同行为和契约的工具。它们在某些方面相似,但在设计理念和功能上有一些区别。
文章目录
抽象类
抽象类是不能被实例化的类,它提供了一个基础类,可以由其他类继承并实现其抽象方法。抽象类允许部分方法有实现,部分方法没有实现(即抽象方法),用于定义子类的共同基础。
特点:
- 抽象类可以有构造方法
- 抽象类可以包含实例变量(字段),并且这些字段可以是不同的访问修饰符(
private
、protected
、public
) - 抽象类可以有已实现的方法(普通方法)
- 抽象类可以有抽象方法(没有方法体),子类必须实现这些方法
- 一个类只能继承一个抽象类(单继承)
实例:
java
abstract class Animal {
// 抽象方法
public abstract void sound();
// 已实现的方法
public void eat() {
System.out.println("动物吃食物");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("狗叫:汪汪");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound(); // 输出:狗叫:汪汪
dog.eat(); // 输出:动物吃食物
}
}
接口
接口是一个纯粹的"契约",它指定了一组方法签名(没有实现),任何实现该接口的类都必须实现这些方法。接口用于定义类之间的协议,它不能包含实例变量(字段),只能包含常量和方法的声明。
特点:
- 接口不能有构造方法
- 接口只能包含抽象方法,Java 8 后,接口可以有默认方法(
default
)和静态方法 - 接口的成员默认都是
public
、static
和final
,即常量 - 一个类可以实现多个接口(多继承)
- 接口用于支持多重继承
示例:
java
interface Animal {
// 抽象方法
void sound();
// 默认方法(Java 8 新特性)
default void eat() {
System.out.println("动物吃食物");
}
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("狗叫:汪汪");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound(); // 输出:狗叫:汪汪
dog.eat(); // 输出:动物吃食物
}
}
抽象类和接口的比较
特性 | 抽象类 | 接口 |
---|---|---|
方法实现 | 可以有已实现的方法,也可以有抽象方法 | 只能有抽象方法(Java 8 后有默认方法) |
成员变量 | 可以有实例变量,并可以定义不同的访问修饰符 | 只能有 public static final 常量 |
构造方法 | 可以有构造方法 | 没有构造方法 |
继承/实现 | 一个类只能继承一个抽象类 | 一个类可以实现多个接口 |
访问修饰符 | 可以是 public 、protected 或 private |
所有方法和变量都是 public 默认 |
用途 | 适用于具有相似功能的类的共性部分 | 适用于不同类之间的协议和行为约定 |
选择使用抽象类还是接口
- 使用抽象类
- 当你需要共享代码,并且有一些默认行为时,使用抽象类
- 如果你想要限制继承的类只能继承一个类,可以使用抽象类(Java 支持单继承)
- 当你有一些实例变量需要在子类中共享时,使用抽象类
- 使用接口
- 当你需要定义一个"协议"或"约定",让不同类实现时,使用接口
- 当你需要支持多重继承时(Java 不支持多继承,但接口支持多实现),可以使用接口
- 当你希望一个类可以实现多个不相关的功能时,可以使用接口