🎯 快速对比表
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract class |
interface |
| 实例化 | ❌ 不能 | ❌ 不能 |
| 继承/实现 | 单继承 | 多实现 |
| 方法类型 | 抽象 + 具体 | 默认只有抽象(Java 8前) |
| 构造器 | ✅ 有 | ❌ 无 |
| 变量 | 任意类型 | 只能是常量 |
| 访问修饰符 | 任意 | 默认 public |
| 设计目的 | 代码复用 + 规范 | 定义契约/能力 |
🔍 相同点
1. 都不能被实例化
java
// 抽象类不能实例化
abstract class AbstractClass {
abstract void method();
}
// 接口不能实例化
interface Interface {
void method();
}
public class CannotInstantiate {
public static void main(String[] args) {
// ❌ 两者都不能直接new
// AbstractClass obj1 = new AbstractClass(); // 编译错误
// Interface obj2 = new Interface(); // 编译错误
}
}
2. 都可以有抽象方法
java
abstract class AnimalClass {
// 抽象类可以有抽象方法
public abstract void makeSound();
}
interface AnimalInterface {
// 接口方法默认是抽象的
void makeSound(); // 等价于 public abstract void makeSound()
}
// 子类/实现类必须实现抽象方法
class Dog extends AnimalClass {
@Override
public void makeSound() {
System.out.println("汪汪");
}
}
class Cat implements AnimalInterface {
@Override
public void makeSound() {
System.out.println("喵喵");
}
}
3. 都支持多态
java
abstract class Shape {
abstract void draw();
}
interface Drawable {
void draw();
}
class Circle extends Shape {
@Override
void draw() {
System.out.println("画圆形");
}
}
class Square implements Drawable {
@Override
public void draw() {
System.out.println("画正方形");
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
// 抽象类的多态
Shape shape = new Circle();
shape.draw(); // 画圆形
// 接口的多态
Drawable drawable = new Square();
drawable.draw(); // 画正方形
// 都可以用数组统一管理
Shape[] shapes = {new Circle()};
Drawable[] drawables = {new Square()};
}
}
⚡ 不同点
1. 继承 vs 实现(核心区别)
java
// 单继承:一个类只能继承一个抽象类
abstract class Vehicle {
abstract void move();
}
abstract class Engine {
abstract void start();
}
class Car extends Vehicle {
// ✅ 正确:只能继承一个抽象类
@Override
void move() {
System.out.println("汽车行驶");
}
}
/*
class HybridCar extends Vehicle, Engine {
// ❌ 错误:不能继承多个抽象类
}
*/
// 多实现:一个类可以实现多个接口
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
// ✅ 正确:可以实现多个接口
@Override
public void fly() {
System.out.println("鸭子飞");
}
@Override
public void swim() {
System.out.println("鸭子游");
}
}
// 组合:可以继承一个类 + 实现多个接口
class AmphibiousVehicle extends Vehicle implements Flyable, Swimmable {
@Override
void move() {
System.out.println("两栖车移动");
}
@Override
public void fly() {
System.out.println("两栖车飞行模式");
}
@Override
public void swim() {
System.out.println("两栖车游泳模式");
}
}
2. 方法实现能力(Java 8+)
java
abstract class AbstractExample {
// 1. 可以有抽象方法
public abstract void abstractMethod();
// 2. 可以有具体方法(一直都可以)
public void concreteMethod() {
System.out.println("抽象类的具体方法");
}
// 3. 可以有构造器
public AbstractExample() {
System.out.println("抽象类构造器");
}
// 4. 可以有静态方法
public static void staticMethod() {
System.out.println("抽象类静态方法");
}
// 5. 可以有final方法
public final void finalMethod() {
System.out.println("抽象类final方法");
}
// 6. 可以有private方法
private void privateMethod() {
System.out.println("抽象类私有方法");
}
}
interface InterfaceExample {
// 1. 抽象方法(Java 8前唯一允许的方法)
void abstractMethod();
// 2. 默认方法(Java 8+)
default void defaultMethod() {
System.out.println("接口的默认方法");
privateMethod(); // 调用私有方法
}
// 3. 静态方法(Java 8+)
static void staticMethod() {
System.out.println("接口的静态方法");
}
// 4. 私有方法(Java 9+)
private void privateMethod() {
System.out.println("接口的私有方法");
}
// 5. 私有静态方法(Java 9+)
private static void privateStaticMethod() {
System.out.println("接口的私有静态方法");
}
// ❌ 不能有构造器
// InterfaceExample() { } // 编译错误
// ❌ 不能有final方法
// final void finalMethod(); // 编译错误
}
class Implementation implements InterfaceExample {
@Override
public void abstractMethod() {
System.out.println("实现抽象方法");
}
}
3. 变量/字段的区别
java
abstract class AbstractVars {
// 1. 可以有实例变量
protected String instanceVar = "实例变量";
// 2. 可以有非常量
private int counter = 0;
// 3. 可以有静态变量
public static String staticVar = "静态变量";
// 4. 可以有final变量
public final String finalVar = "final变量";
// 5. 访问修饰符可以是任意的
private String privateVar = "私有变量";
protected String protectedVar = "受保护变量";
String defaultVar = "默认变量";
public String publicVar = "公共变量";
}
interface InterfaceVars {
// 1. 所有变量默认是 public static final
String CONSTANT = "常量";
// 等价于:
// public static final String CONSTANT = "常量";
// ❌ 不能有实例变量
// String instanceVar; // 编译错误
// ❌ 不能有非final变量
// int counter = 0; // 实际上是常量
// 2. 只能是public
// private String privateVar = "错误"; // 编译错误
// protected String protectedVar = "错误"; // 编译错误
}
public class VariablesDemo {
public static void main(String[] args) {
System.out.println("抽象类变量: " + AbstractVars.staticVar);
System.out.println("接口常量: " + InterfaceVars.CONSTANT);
// 接口常量不能修改
// InterfaceVars.CONSTANT = "新值"; // 编译错误
}
}
4. 构造器的区别
java
abstract class AbstractWithConstructor {
private String name;
// 抽象类可以有构造器
public AbstractWithConstructor(String name) {
this.name = name;
System.out.println("抽象类构造器调用: " + name);
}
public abstract void doSomething();
public String getName() {
return name;
}
}
class ConcreteClass extends AbstractWithConstructor {
// 子类必须调用父类构造器
public ConcreteClass(String name) {
super(name); // 必须调用
}
@Override
public void doSomething() {
System.out.println(getName() + "在做事情");
}
}
interface NoConstructor {
// ❌ 接口不能有构造器
// NoConstructor() { } // 编译错误
void method();
}
public class ConstructorDemo {
public static void main(String[] args) {
ConcreteClass obj = new ConcreteClass("测试");
obj.doSomething();
}
}
5. 访问修饰符的区别
java
abstract class AccessModifiers {
// 所有访问修饰符都可以用
private void privateMethod() {}
void defaultMethod() {}
protected void protectedMethod() {}
public void publicMethod() {}
// 抽象方法不能是private
// private abstract void privateAbstract(); // 编译错误
protected abstract void protectedAbstract();
public abstract void publicAbstract();
}
interface InterfaceAccess {
// 接口方法默认是public
void method(); // 等价于 public abstract void method()
// Java 9+ 可以有private方法
private void privateMethod() {
System.out.println("接口私有方法");
}
// 不能是protected或默认
// protected void protectedMethod(); // 编译错误
// void defaultMethod(); // 编译错误(Java 8前)
// Java 8+ 默认方法可以是public
default void defaultPublicMethod() {
System.out.println("默认公共方法");
}
}
💡 何时使用抽象类 vs 接口
1. 使用抽象类的情况
java
// 场景1:多个相关类共享代码
abstract class Database {
// 共享的连接逻辑
protected Connection connect(String url) {
System.out.println("连接到: " + url);
return new Connection();
}
// 共享的关闭逻辑
protected void close(Connection conn) {
System.out.println("关闭连接");
}
// 模板方法
public final void executeQuery(String sql) {
Connection conn = connect(getUrl());
try {
execute(sql, conn);
} finally {
close(conn);
}
}
// 子类必须实现
protected abstract String getUrl();
protected abstract void execute(String sql, Connection conn);
}
class MySQLDatabase extends Database {
@Override
protected String getUrl() {
return "jdbc:mysql://localhost:3306/db";
}
@Override
protected void execute(String sql, Connection conn) {
System.out.println("执行MySQL查询: " + sql);
}
}
class OracleDatabase extends Database {
@Override
protected String getUrl() {
return "jdbc:oracle:thin:@localhost:1521:orcl";
}
@Override
protected void execute(String sql, Connection conn) {
System.out.println("执行Oracle查询: " + sql);
}
}
2. 使用接口的情况
java
// 场景1:定义能力/契约
interface Comparable<T> {
int compareTo(T other);
}
interface Serializable {
// 标记接口
}
interface Cloneable {
// 标记接口
}
// 场景2:多重继承
interface Worker {
void work();
}
interface Student {
void study();
}
interface Athlete {
void train();
}
class CollegeStudent implements Student, Worker, Athlete {
@Override
public void work() {
System.out.println("兼职工作");
}
@Override
public void study() {
System.out.println("学习课程");
}
@Override
public void train() {
System.out.println("体育训练");
}
}
// 场景3:回调机制
interface ClickListener {
void onClick();
}
interface TextChangedListener {
void onTextChanged(String newText);
}
class Button {
private ClickListener listener;
public void setClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
if (listener != null) {
listener.onClick();
}
}
}
3. 结合使用(常见模式)
java
// 抽象类提供骨架实现
abstract class AbstractList<E> implements List<E> {
// 提供通用实现
public boolean add(E e) {
add(size(), e);
return true;
}
// 抽象方法由子类实现
public abstract void add(int index, E element);
public abstract E get(int index);
public abstract int size();
}
// 接口定义契约
interface List<E> {
boolean add(E e);
void add(int index, E element);
E get(int index);
int size();
}
// 具体实现
class ArrayList<E> extends AbstractList<E> {
private Object[] elements = new Object[10];
private int size = 0;
@Override
public void add(int index, E element) {
// 实现细节
System.out.println("ArrayList添加元素");
}
@Override
public E get(int index) {
// 实现细节
return null;
}
@Override
public int size() {
return size;
}
}
public class CombinedUsage {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
System.out.println("大小: " + list.size());
}
}
📝 现代Java中的变化(Java 8+)
接口的增强
java
// Java 8 前:接口只能有抽象方法
interface OldInterface {
void method(); // 只能是抽象方法
}
// Java 8+:接口可以有多样方法
interface ModernInterface {
// 1. 抽象方法
void abstractMethod();
// 2. 默认方法
default void defaultMethod() {
System.out.println("默认实现");
privateMethod();
}
// 3. 静态方法
static void staticMethod() {
System.out.println("静态方法");
privateStaticMethod();
}
// 4. 私有方法(Java 9+)
private void privateMethod() {
System.out.println("私有实例方法");
}
// 5. 私有静态方法(Java 9+)
private static void privateStaticMethod() {
System.out.println("私有静态方法");
}
}
// 现在接口 ≈ 抽象类,但仍有区别:
// 1. 接口仍然不能有构造器
// 2. 接口仍然不能有实例变量
// 3. 接口仍然支持多重继承
🎓 记忆口诀
markdown
相同点:
1. 都不能new(不能实例化)
2. 都能有抽象方法
3. 都支持多态
不同点:
抽象类:
- 单继承
- 有构造器
- 有具体方法(一直都有)
- 有各种变量
- 设计:是什么(is-a)
接口:
- 多实现
- 无构造器
- 默认方法(Java 8+)
- 只有常量
- 设计:能什么(has-a/can-do)
💡 实用建议
选择指南
markdown
问自己这些问题:
1. 需要多重继承吗?
- 是 → 用接口
- 否 → 继续
2. 需要共享代码吗?
- 是 → 用抽象类
- 否 → 用接口
3. 相关类有紧密关系吗?
- 是 → 用抽象类
- 否 → 用接口
4. 只是定义契约吗?
- 是 → 用接口
- 否 → 继续
5. 需要控制子类构造吗?
- 是 → 用抽象类
- 否 → 用接口
最佳实践
java
// 优先使用接口(更加灵活)
public interface Repository<T> {
void save(T entity);
T findById(int id);
List<T> findAll();
}
// 需要共享代码时使用抽象类
public abstract class AbstractRepository<T> implements Repository<T> {
protected DatabaseConnection connection;
public AbstractRepository(DatabaseConnection connection) {
this.connection = connection;
}
// 共享的保存逻辑
@Override
public void save(T entity) {
validate(entity);
persist(entity);
logSave(entity);
}
protected abstract void persist(T entity);
private void validate(T entity) {
// 验证逻辑
}
private void logSave(T entity) {
// 日志逻辑
}
}
// 具体实现
public class UserRepository extends AbstractRepository<User> {
public UserRepository(DatabaseConnection connection) {
super(connection);
}
@Override
protected void persist(User entity) {
// 具体持久化逻辑
}
@Override
public User findById(int id) {
// 具体查找逻辑
return null;
}
@Override
public List<User> findAll() {
// 具体查找逻辑
return new ArrayList<>();
}
}
记住:现代Java开发中,优先考虑使用接口,只有在确实需要共享代码时才使用抽象类。接口提供了更大的灵活性和可扩展性!