核心一句话:抽象类是 “类”,代表一种「是什么」的继承关系(is-a);接口是行为规范,代表「能做什么」(can-do)
一、抽象类和接口的区别
| 对比项 | 抽象类 abstract class | 接口 interface |
|---|---|---|
| 关键字 | abstract class | interface |
| 继承 | 单继承 extends多实现 | implements;接口可多继承 |
| 构造器 | 有构造方法 | 无构造方法 |
| 成员变量 | 任意修饰符,可读写默认 | public static final,常量 |
| 抽象方法权限 | protected/public默认 | public |
| 关系 | is-a(是一种) | can-do(具备某种能力) |
| 代码复用 | 可以复用成员变量、普通方法 | 侧重定义规范,Java8+default 方法可复用逻辑 |
⚠️1. 抽象类不一定包含抽象方法:一个类带 abstract 就是抽象类,可以全是普通方法
2. 接口不能有实例变量
3. 优先使用接口;当存在大量公共字段 / 公共逻辑时,才考虑抽象类
二、举例说明(Java语言)
1. 抽象类:abstract class
// 抽象类
abstract class Animal {
// 普通成员变量
String name;
// 构造方法,抽象类不能new,但子类会调用
public Animal(String name) {
this.name = name;
}
// 普通方法(有方法体,子类直接复用)
public void sleep() {
System.out.println(name + " 在睡觉");
}
// 抽象方法:没有方法体,子类必须重写
public abstract void eat();
}
// 子类继承抽象类
class Dog extends Animal {
public Dog(String name) {
super(name);
}
// 必须实现抽象方法
@Override
public void eat() {
System.out.println(name + " 吃骨头");
}
}
// 测试
public class TestAbstract {
public static void main(String[] args) {
Animal dog = new Dog("旺财");
dog.sleep();
dog.eat();
}
}
运行结果
旺财 在睡觉
旺财 吃骨头
2. 接口: interface(Java8)
// 接口:定义“会跑”这个能力
interface Runnable {
// 抽象方法,实现类必须重写
void run();
}
// 实现类,实现接口
class Rabbit implements Runnable {
@Override
public void run() {
System.out.println("兔子蹦蹦跳跳地跑");
}
}
// 测试
public class TestInterface {
public static void main(String[] args) {
Runnable rabbit = new Rabbit();
rabbit.run();
}
}
运行结果
兔子蹦蹦跳跳地跑
扩展:接口【多实现】
一个类可以同时实现多个接口,这是和抽象类最大区别之一
interface Runnable {
void run();
}
interface Swimmable {
void swim();
}
// 鸭子,既能跑也能游泳
class Duck implements Runnable, Swimmable {
@Override
public void run() {
System.out.println("鸭子摇摇摆摆跑");
}
@Override
public void swim() {
System.out.println("鸭子在水里游");
}
}
public class TestMultiInterface {
public static void main(String[] args) {
Duck duck = new Duck();
duck.run();
duck.swim();
}
}
运行结果
鸭子摇摇摆摆跑
鸭子在水里游
3.抽象类+接口 混合案例
// 抽象类:动物 is‑a 是什么
abstract class Animal {
protected String name;
// 抽象类构造方法,供子类调用
public Animal(String name) {
this.name = name;
}
// 普通公共方法,子类直接复用
public void sleep() {
System.out.println(name + " 在睡觉");
}
// 抽象方法,子类必须重写
public abstract void eat();
}
// 接口:游泳能力 can‑do 能做什么
interface Swim {
void swim();
}
// 鸭子:继承抽象类,同时实现接口
class Duck extends Animal implements Swim {
public Duck(String name) {
super(name);
}
// 重写抽象类的抽象方法 eat
@Override
public void eat() {
System.out.println(name + " 吃小虫");
}
// 实现接口的抽象方法 swim
@Override
public void swim() {
System.out.println(name + " 在水里游泳");
}
}
// 测试
public class Demo {
public static void main(String[] args) {
Duck duck = new Duck("小黄鸭");
duck.sleep(); // 来自抽象类普通方法
duck.eat(); // 重写抽象类方法
duck.swim(); // 实现接口方法
}
}
运行结果
小黄鸭 在睡觉
小黄鸭 吃小虫
小黄鸭 在水里游泳
小结
- 抽象类描述事物
is‑a从属关系,用于抽取子类公共属性与通用代码,依靠extends单继承; - 接口定义行为能力
can‑do,依靠implements实现多实现,只保存常量与行为规范。 - 实际开发经常组合使用:继承抽象类复用公共代码,同时实现接口扩展额外能力。
- 优先选择接口;子类存在大量公共字段与逻辑时,选用抽象类。