当前位置: 首页 > backend >正文

java接口和抽象类有何区别

一、抽象类(Abstract Class)

抽象类是一种不能被实例化的类,主要用于作为其他类的基类(父类),用来抽取子类的通用特性和行为。

1.1 主要特点

  •  

    ​定义方式​​:使用 abstract关键字修饰类。

  •  

    ​包含内容​​:

    •  

      ​抽象方法​​:使用 abstract关键字修饰,只有声明没有实现(没有方法体),必须由子类提供实现。

    •  

      ​具体方法​​:可以有实现了的方法(非抽象方法),子类可以直接继承或重写。

    •  

      ​成员变量​​:可以包含普通成员变量(实例变量)和静态变量,变量的访问修饰符可以是 publicprotecteddefault(包私有),但不能是 private(对于抽象方法)。

    •  

      ​构造方法​​:可以有构造方法,用于初始化抽象类中定义的成员变量或供子类调用。但抽象类的构造方法不能直接用于实例化自身,只能由子类的构造方法调用。

    •  

      ​初始化块​​:可以包含初始化块。

  •  

    ​继承​​:类通过 extends关键字继承抽象类。Java 是单继承,一个类只能直接继承一个抽象类(但可以多层继承)。

1.2 设计目的与使用场景

抽象类主要用于​​代码复用​​和表示 ​​"is-a"(是一个)​​ 的关系

。它适合为一组密切相关的类提供统一的模板或基类,这些类共享一些共同的属性和行为,但又有一些特定的行为需要各自实现。

​典型使用场景​​:

  •  

    ​模板方法模式​​:在抽象类中定义算法的骨架(一个最终的具体方法),并将一些步骤延迟到子类中实现。

  •  

    ​家族式对象建模​​:为具有共同特征和行为的对象族定义基础类,如 Animal抽象类被 DogCat等子类继承。

  •  

    ​共享代码和状态​​:当多个子类需要共享一些通用的方法实现或成员变量时。

1.3 代码示例

// 抽象类示例:Animal
abstract class Animal {// 成员变量protected String name;// 构造方法public Animal(String name) {this.name = name;}// 抽象方法(无方法体)public abstract void makeSound();// 具体方法(有方法体)public void sleep() {System.out.println(name + " is sleeping.");}
}// 具体子类:Dog
class Dog extends Animal {public Dog(String name) {super(name);}@Overridepublic void makeSound() {System.out.println(name + " says: Woof!");}
}

二、接口(Interface)

接口是一种完全抽象的类型,用于声明一组方法(行为契约),要求实现类必须提供这些方法的具体实现。

2.1 主要特点 (以Java 8为基准)

  •  

    ​定义方式​​:使用 interface关键字声明。

  •  

    ​包含内容​​:

    •  

      ​抽象方法​​:在 Java 8 之前,接口中的所有方法都是隐式 public abstract的(无需显式写这两个关键字)。

    •  

      ​默认方法 (Default Methods)​​:Java 8 引入,使用 default关键字修饰,提供默认实现。实现类可以重写,也可以直接继承。

    •  

      ​静态方法 (Static Methods)​​:Java 8 引入,使用 static关键字修饰,可以通过接口名直接调用。

    •  

      ​私有方法 (Private Methods)​​:Java 9 引入,用于在接口内部封装代码,供默认方法或静态方法使用。

    •  

      ​成员变量​​:接口中定义的变量默认为 public static final的常量,必须显式初始化。

    •  

      ​构造方法​​:接口​​不能​​有构造方法。

    •  

      ​初始化块​​:接口​​不能​​包含初始化块。

  •  

    ​实现与继承​​:

    •  

      类使用 implements关键字实现一个或多个接口(多重继承)。

    •  

      接口使用 extends关键字继承其他接口,并且可以同时继承多个接口。

2.2 设计目的与使用场景

接口主要用于定义​​行为契约​​(协议)和表示 ​​"can-do"(能做什么)​​ 或 ​​"like-a"(像是一个)​​ 的关系

。它关注于对象能做什么,而不关心对象是什么,实现了接口与实现的解耦。

​典型使用场景​

  •  

    ​定义API契约​​:如定义支付网关、数据访问层等规范。

  •  

    ​实现多态​​:让不相关的类能够表现出相同的行为。

  •  

    ​回调机制​​:如事件监听器。

  •  

    ​替代多重继承​​:Java 类可以通过实现多个接口来获得多种类型的行为。

2.3 代码示例

// 接口示例:Flyable
interface Flyable {// 抽象方法 (隐式 public abstract)void fly();// 默认方法 (Java 8+)default void takeOff() {System.out.println("Preparing to fly...");}// 静态方法 (Java 8+)static boolean isFlyingObject(Object obj) {return obj instanceof Flyable;}// 常量 (隐式 public static final)String UNIT = "meters";
}// 实现类:Bird
class Bird implements Flyable {@Overridepublic void fly() {System.out.println("Bird is flying in the sky.");}
}// 另一个不相关的实现类:Airplane
class Airplane implements Flyable {@Overridepublic void fly() {System.out.println("Airplane is flying in the air.");}
}

三、抽象类与接口的对比

为了让区别更直观,下面用一个表格来概括它们的核心差异

特性维度

抽象类 (Abstract Class)

接口 (Interface) (Java 8+)

​关键字​

abstract class

interface

​继承/实现​

单继承 (extends)

多实现 (implements)

​方法类型​

抽象方法 + 具体方法

抽象方法 + 默认方法 (default) + 静态方法 (static) + 私有方法 (private, Java9+)

​成员变量​

普通成员变量、静态变量

只能是 public static final常量

​构造方法​

​初始化块​

​设计理念/关系​

​is-a​​ (是一个),强调​​代码复用​​和​​分类​

​can-do​​/​​like-a​​ (能做什么/像是一个),强调​​行为契约​​和​​解耦​

​访问修饰符(方法)​

抽象方法可以是 publicprotecteddefault

方法默认 public(可省略),不可用其他修饰符

​主要用途​

作为模板,提取同类公共特性,部分实现

定义行为规范,实现多重契约

​版本兼容性​

添加新方法可能需修改子类

Java 8+ 后可通过默认方法添加新功能而不破坏现有实现

四、如何选择:抽象类 vs 接口

选择使用抽象类还是接口,甚至结合使用,取决于你的具体设计需求

  1.  

    ​使用抽象类的情况​​:

    • 需要​​共享代码​​或​​状态​​(成员变量) among closely related classes.

    • 需要定义​​非公共的方法​​(protected或 default访问权限)。

    • 正在建模的类之间存在明显的 ​​"is-a"​​ 层次关系(如 Dogis an Animal)。

    • 想通过​​模板方法模式​​定义算法的骨架。

  2.  

    ​使用接口的情况​​:

    • 需要定义​​不相关类​​都能实现的​​行为契约​​。

    • 需要实现​​多重继承​​(多重行为类型)。

    • 希望实现​​与实现的解耦​​,更注重API的定义而非具体实现。

    • 想使用​​多态​​特性,让不同类型的对象对外提供相同的行为方式。

  3.  

    ​结合使用​​:

    一个类可以同时继承一个抽象类并实现多个接口,这常常能带来灵活而强大的设计。

    // 结合使用示例
    abstract class Vehicle {protected int speed;public abstract void start();
    }interface ElectricPowered {void charge();
    }class ElectricCar extends Vehicle implements ElectricPowered {@Overridepublic void start() { System.out.println("Electric car starting..."); }@Overridepublic void charge() { System.out.println("Charging the electric car..."); }
    }

​核心选择原则​​:

  •  

    ​关系类型​​:"是什么" -> 抽象类;"能做什么" -> 接口。

  •  

    ​代码共享​​:需要 -> 抽象类;不需要 -> 接口。

  •  

    ​状态共享​​:需要 -> 抽象类;不需要 -> 接口。

  •  

    ​多重继承​​:需要 -> 接口;不需要 -> 两者皆可,但需进一步判断。

五、总结

  •  

    ​抽象类​​更像是一个​​不完全的类​​,为相关类提供公共基础和模板,侧重于​​代码复用和内部状态管理​​。

  •  

    ​接口​​更像是一个​​行为协议​​,定义了实现类应对外提供哪些服务,侧重于​​契约定义和解耦​​。

  •  

    ​现代Java设计​​(尤其是Java 8引入默认方法后)更倾向于 ​​"面向接口编程"​​,优先考虑使用接口定义类型,以提高灵活性和可扩展性。抽象类则更适用于框架内部或存在明显继承关系的类族中,用于封装公共实现。

  •  

    在设计时,​​组合(通过接口)优于继承​​是一个值得遵循的原则,它能降低耦合度。

http://www.xdnf.cn/news/20272.html

相关文章:

  • ICPC 2023 Nanjing R L 题 Elevator
  • 用Android studio运行海外极光推送engagelab安卓的SDK打apk安装包
  • Ribbon和LoadBalance-负载均衡
  • 从Java全栈到前端框架:一次真实面试的深度复盘
  • 验证平台中所有的组件应该派生自UVM中的类
  • 设计艺术~缓存结构设计
  • 【Go项目基建】GORM框架实现SQL校验拦截器(完整源码+详解)
  • C++和OpenGL实现3D游戏编程【连载30】——文字的多行显示
  • MySQL集群——主从复制进阶
  • 2025年上海市星光计划第十一届职业院校技能大赛高职组“信息安全管理与评估”赛项交换部分前6题详解(仅供参考)
  • FlashAttention:突破Transformer内存瓶颈的IO感知革命
  • Web漏洞挖掘篇(二)—信息收集
  • 浪潮CD1000-移动云电脑-RK3528芯片-2+32G-安卓9-2种开启ADB ROOT刷机教程方法
  • Chat with RTX-NVIDIA推出的本地AI聊天机器人
  • .NET Core 应用部署深度解析:从 IIS 到 Docker+Kestrel 的迁移与性能优化实战
  • 电脑音频录制 | 系统麦克混录 / 系统声卡直录 | 方法汇总 / 常见问题
  • Unity与硬件交互终极指南:从Arduino到自定义USB设备
  • 零基础Linux操作基础小白快速掌握Shell脚本--流程控制和循环(二)
  • CAD:注释
  • PPTist,一个完全免费的 AI 生成 PPT 在线网站
  • 贪心算法应用:流行病干预策略问题详解
  • redis的数据类型:Hash
  • 【数据结构】带哨兵位双向循环链表
  • 50系显卡训练深度学习YOLO等算法报错的解决方法
  • 《动手学深度学习v2》学习笔记 | 2.4 微积分 2.5 自动微分
  • 深度学习——PyTorch保存模型与调用模型
  • JUC之并发编程
  • MyBatis入门到精通:CRUD实战指南
  • 使用UniApp实现下拉框和表格组件页面
  • Android Kotlin 动态注册 Broadcast 的完整封装方案