• 实现方式:实现接口的关键字为 implements,继承抽象类的关键字为 extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
  • 方法方式:接口只有定义,不能有方法的实现;而抽象类可以有定义与实现,方法可在抽象类中实现。
  • 访问修饰符:接口成员变量默认为 public static final,必须赋初值,不能被修改;接口中的抽象方法默认是 public abstract;抽象方法被 abstract修饰,不能被private、static、synchronized和native` 等修饰,必须以分号结尾,不带花括号。
  • 变量:抽象类可以包含实例变量和静态变量,而接口只能包含常量(即静态常量)。

抽象类:

// 抽象类,用 abstract 修饰,不能 new 实例
abstract class BaseVoucher {
    // 普通实例变量(抽象类可以有实例成员)
    protected String name;

    // 普通方法:有方法体,子类直接继承复用
    public void printInfo() {
        System.out.println("优惠券名称:" + name);
    }

    // 抽象方法:没有方法体,必须让子类重写,abstract关键字
    public abstract void doSeckill();
}

// 子类继承抽象类,extends
class SeckillVoucher extends BaseVoucher{

    // 必须重写父类的抽象方法
    @Override
    public void doSeckill() {
        System.out.println("执行秒杀券业务逻辑");
    }
}

public class TestAbstract {
    public static void main(String[] args) {
        // BaseVoucher base = new BaseVoucher(); // ❌ 抽象类不能实例化
        BaseVoucher voucher = new SeckillVoucher(); // ✅向上转型,多态
        voucher.doSeckill();
    }
}

接口:

// 接口
interface IVoucher {
    // 接口里的变量:默认 public static final,常量,必须初始化,不能修改
    String TYPE = "优惠券";

    // 抽象方法:默认 public abstract,没有方法体,实现类必须重写
    void doSeckill();
}

// 实现类,implements,可以同时实现多个接口
class SeckillVoucherImpl implements IVoucher{
    // 重写接口抽象方法
    @Override
    public void doSeckill() {
        System.out.println("秒杀券实现逻辑");
    }
}

public class TestInterface {
    public static void main(String[] args) {
        IVoucher voucher = new SeckillVoucherImpl(); // ✅向上转型,多态
        voucher.doSeckill();
        voucher.printType();
        IVoucher.desc(); // 静态方法只能接口名调用
    }
}

Question:抽象类能加 final 修饰吗?

不能,Java 中的抽象类是用来被继承的,而 final 修饰符用于禁止类被继承或方法被重写,因此,抽象类和 final 修饰符是互斥的,不能同时使用。

Question:抽象类可以被实例化吗?

不可以,不能用 new 关键词直接创建抽象类对象。抽象类的存在是为了被继承。抽象类可以有构造函数

Question:接口可以包含构造函数吗?

不可以有构造方法。
抽象类本质还是类,类都需要构造器;接口不是类,只是一套行为规范,没有实例,不需要构造期。