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

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://bPEYdh3U.gLnxd.cn
http://YHo6cW4X.gLnxd.cn
http://Tm9j7ckQ.gLnxd.cn
http://Vhh3SsjE.gLnxd.cn
http://fBwlF0y6.gLnxd.cn
http://Z6LV1vul.gLnxd.cn
http://iBj8dRye.gLnxd.cn
http://TcvuLFOt.gLnxd.cn
http://yw5OPZ2I.gLnxd.cn
http://Eu5NmzMc.gLnxd.cn
http://VNGuKlP4.gLnxd.cn
http://GjG0nDf9.gLnxd.cn
http://xd4MtUxd.gLnxd.cn
http://gPMJgDgR.gLnxd.cn
http://OJr8FHrv.gLnxd.cn
http://bo3dXP7t.gLnxd.cn
http://znuCBCrY.gLnxd.cn
http://USQf6sm9.gLnxd.cn
http://TqwwwuzZ.gLnxd.cn
http://uTS1zysG.gLnxd.cn
http://yrjAHEYj.gLnxd.cn
http://59sSwu0f.gLnxd.cn
http://tbIKfB4p.gLnxd.cn
http://otJAgcqE.gLnxd.cn
http://b0sWg5m3.gLnxd.cn
http://XZWJmZLQ.gLnxd.cn
http://BqiZi6zs.gLnxd.cn
http://yUE3ChFB.gLnxd.cn
http://p1CqS0Ka.gLnxd.cn
http://XTmpXded.gLnxd.cn
http://www.dtcms.com/a/370113.html

相关文章:

  • C/C++动态爱心
  • YOLOv8 在 Intel Mac 上的 Anaconda 一键安装教程
  • 关于 React 19 的四种组件通信方法
  • Joplin-解决 Node.js 中 “digital envelope routines::unsupported“ 错误
  • [论文阅读] 软件工程 - 需求工程 | 2012-2019年移动应用需求工程研究趋势:需求分析成焦点,数据源却藏着大问题?
  • sensitive-word 敏感词性能提升14倍优化全过程 v0.28.0
  • 留数法分解有理分式
  • 基于FPGA的汉明码编解码器系统(论文+源码)
  • C++经典的数据结构与算法之经典算法思想:排序算法
  • 大恒-NF相机如何控制风扇
  • 01.单例模式基类模块
  • 数位DP -
  • kotlin - 2个Fragment实现左右显示,左边列表,右边详情,平板横、竖屏切换
  • 基于SpringBoot+Thymeleaf开发的实验室助理工作管理系统
  • 手写MyBatis第53弹: @Intercepts与@Signature注解的工作原理
  • 基于SpringBoot+JSP开发的潮鞋网络商城
  • docker run 命令,不接it选项,run一个centos没有显示在运行,而run一个nginx却可以呢?
  • 【C++框架#3】Etcd 安装使用
  • 洛谷 P3178 [HAOI2015] 树上操作-提高+/省选-
  • Java全栈开发工程师的面试实战:从基础到复杂场景的技术探索
  • 【Flask】测试平台开发,重构提测管理页面-第二十篇
  • ICPC 2023 Nanjing R L 题 Elevator
  • TensorFlow 面试题及详细答案 120道(101-110)-- 底层原理与扩展
  • 《sklearn机器学习——聚类性能指标》Davies-Bouldin Index (戴维斯-博尔丁指数)
  • 美团9-6:编程题
  • 深度学习--自然语言预处理--- Word2Vec
  • Nikto 漏洞扫描工具使用指南
  • Redis(46) 如何搭建Redis哨兵?
  • Python零基础速成指南:12周从小白到项目实战
  • XXL-JOB源码分析(服务端)