抽象类和接口的区别有哪些以及抽象类和接口的使用方法

9 阅读3分钟

核心一句话:抽象类是 “类”,代表一种「是什么」的继承关系(is-a);接口是行为规范,代表「能做什么」(can-do)

一、抽象类和接口的区别

对比项抽象类 abstract class接口 interface
关键字abstract classinterface
继承单继承 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实现多实现,只保存常量与行为规范。
  • 实际开发经常组合使用:继承抽象类复用公共代码,同时实现接口扩展额外能力。
  • 优先选择接口;子类存在大量公共字段与逻辑时,选用抽象类。