抽象类和接口的区别
一、基本定义
- 抽象类(abstract class)
- 一种不能被实例化的类,用来被子类继承。
- 可以包含 抽象方法(没有方法体,需要子类实现)和 具体方法。
- 适用于描述“is-a”关系(是一种)。
- 接口(interface)
- 一种更纯粹的抽象定义,规定了一组方法的“契约”。
- Java 8 之前只能有抽象方法;Java 8+ 支持 default 方法、static 方法,Java 9+ 支持 private 方法。
- 适用于描述“has-a”或“can-do”关系(能做什么)。
二、主要区别(对比表)
对比点 | 抽象类 | 接口 |
关键字 | abstract class | interface |
继承/实现 | 子类用extends,单继承 | 类用 implements,多实现 |
成员变量 | 可以有实例变量(普通字段) | 只能有静态常量(public static final) |
方法 | 可以有抽象方法 + 普通方法 | 默认方法全是public abstract(Java8 起支持default/static方法) |
构造方法 | 可以有构造方法(但不能直接实例化) | 不能有构造方法 |
访问修饰符 | 抽象方法可以是 public/protected | 方法默认 public abstract,不能是protected/private |
继承限制 | 只能单继承一个抽象类 | 可以实现多个接口 |
设计层面 | 模板,提供“基础实现” | 纯契约,强调“能力”扩展 |
实例化区别
对比点 | 接口(interface) | 抽象类(abstract class) |
能否直接 new | 不能直接new | 不能直接new |
方式 1:实现类 | 通过implements实现类实例化PayService pay = new AliPayService(); | 通过 extends 子类实例化 Animal dog = new Dog(); |
方式 2:匿名内部类 | PayService pay = new ayService() { public void pay(double a){...} }; | Animal cat = new Animal() { void sound(){...} }; |
方式 3:Lambda 表达式 | 仅限函数式接口Runnable r = () -> {...}; | 不支持(因为可能有多个抽象方法) |
方式 4:动态代理 | 常见于 Spring AOP / MyBatis Proxy.newProxyInstance(...); | 一般不用动态代理(框架里常用工厂模式) |
方式 5:框架工厂/模板方法 | 通过 IOC 容器注入接口代理类(Spring Service Bean) | 通过工厂方法返回子类实例(SpringAbstractApplicationContext) |
本质 | 依靠实现类才能有对象 | 依靠子类才能有对象 |
接口:靠“实现类” + “匿名类” + “Lambda” + “动态代理”。
抽象类:靠“子类” + “匿名类” + “工厂模式”。
共同点:都不能直接 new,必须依赖子类/实现类。
三、使用场景
抽象类适用场景
- 当类之间存在强烈的继承关系,有 共享的字段和方法。
- 父类提供 部分默认实现,子类只需实现差异化部分。
- 示例:Spring 中的 HttpServlet,它是抽象类,提供了很多默认实现,子类只需实现 doGet / doPost。
public abstract class Animal {String name;public void eat() { System.out.println("eating..."); }public abstract void sound();
}public class Dog extends Animal {@Overridepublic void sound() { System.out.println("Bark"); }
}
接口适用场景
- 当需要定义一种 行为规范,不同类可以有不同的实现。
- 常用于 解耦,强调“能做什么”而不是“是什么”。
- 示例:Spring 中的 BeanFactory、ApplicationContext 都是接口,不同实现类(如 XmlApplicationContext、AnnotationConfigApplicationContext)可以自由扩展。
public interface PayService {void pay(double amount);
}public class AliPayService implements PayService {@Overridepublic void pay(double amount) { System.out.println("AliPay: " + amount); }
}public class WeChatPayService implements PayService {@Overridepublic void pay(double amount) { System.out.println("WeChatPay: " + amount); }
}
四、总结
- 抽象类:是一种 模板,强调 继承,可以有状态(成员变量)。
- 接口:是一种 契约,强调 规范,只能定义能力(方法)。
- 项目中:
- 抽象类 → 用来封装一类事物的通用逻辑。
- 接口 → 用来定义规范,解耦调用方和实现方。
- “动物”是一个抽象类,因为它有共同属性和部分方法(名字、吃饭)。
- “会飞的东西”是一个接口,因为鸟、飞机、超级英雄都能实现“Flyable”,但它们并没有统一的父类。