抽象类与接口
在面向对象编程(OOP)中,抽象类(Abstract Class) 和 接口(Interface) 是两种定义类的方式,它们都可以用于定义规范,但它们有一些重要的区别。
1. 抽象类(Abstract Class)
定义:
- 抽象类是不能被实例化的类,通常包含至少一个抽象方法(没有方法体的函数)。
- 主要用于提供基本实现,并允许子类继承。
- 既可以包含普通方法(有方法体),也可以包含抽象方法(只有方法声明,没有方法体)。
特点:
- 不能实例化,只能被继承。
- 可以包含普通方法和抽象方法。
- 可以有成员变量(字段),可以定义构造函数。
- 可以有访问修饰符(public、protected、private)。
示例(Java):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35abstract class Animal {
String name;
// 构造方法
Animal(String name) {
this.name = name;
}
// 具体方法
void eat() {
System.out.println(name + " is eating.");
}
// 抽象方法(子类必须实现)
abstract void makeSound();
}
class Dog extends Animal {
Dog(String name) {
super(name);
}
@Override
void makeSound() {
System.out.println("Woof Woof!");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.eat(); // 继承的普通方法
dog.makeSound(); // 实现的抽象方法
}
}
2. 接口(Interface)
定义:
- 接口是一个完全抽象的类,所有方法默认都是抽象的(Java 8 之后支持默认方法)。
- 主要用于定义行为规范,而不提供实现,由实现接口的类提供具体实现。
特点:
- 不能实例化,只能被类实现(
implements
)。 - 所有方法默认是
public abstract
(即使不写public abstract
关键字)。 - 不能包含普通方法(Java 8 之后可以有默认方法
default
)。 - 不能有成员变量,但可以有
public static final
常量。 - 一个类可以实现多个接口(支持多继承)。
示例(Java):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19interface Animal {
// 默认是 public abstract
void makeSound();
}
// 接口实现
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow Meow!");
}
}
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.makeSound();
}
}
3. 主要区别
对比项 抽象类 接口 实例化 不能被实例化 不能被实例化 方法 可以有普通方法和抽象方法 只能有抽象方法(Java 8+ 允许默认方法) 成员变量 可以有变量(实例变量、静态变量) 只能有 public static final
常量构造函数 可以有构造函数 不能有构造函数 继承关系 只能单继承( extends
)可以多实现( implements
)使用场景 用于共享代码和定义行为 用于定义规范,让不同类实现相同行为
4. 什么时候用?
✅ 用抽象类:
- 当多个类有共同的部分实现(代码复用),但仍然需要在子类中提供具体实现时。
- 当希望限制继承,只允许单一继承时。
✅ 用接口:
- 当需要多个类具有相同行为,但它们本身可能没有共同的父类。
- 当需要多继承时(Java 不支持类的多继承,但支持接口的多实现)。
- 当需要定义一个严格的行为规范时。
5. 结合使用
有时候,可以结合 抽象类 和 接口,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24interface Flyable {
void fly();
}
abstract class Bird {
void eat() {
System.out.println("Bird is eating.");
}
abstract void makeSound();
}
// 继承抽象类 & 实现接口
class Sparrow extends Bird implements Flyable {
@Override
void makeSound() {
System.out.println("Chirp Chirp!");
}
@Override
public void fly() {
System.out.println("Sparrow is flying.");
}
}这里
Sparrow
继承Bird
(因为所有鸟都可以吃东西),但也实现了Flyable
接口,因为不是所有鸟都会飞(如企鹅)。
6. 结论
- 抽象类 适用于父类提供部分实现,子类扩展功能的情况。
- 接口 适用于定义行为规范,让多个不相关的类实现相同方法的情况。
- 接口比抽象类更灵活,因为它允许多实现。
💡 记住:如果是**“是什么”(继承关系),用抽象类**;如果是**“能做什么”(行为规范),用接口**。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Firefly!