Java中接口和抽象类的异同以及具体的使用场景

2025-11-17 18:50

本文主要是介绍Java中接口和抽象类的异同以及具体的使用场景,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java中接口和抽象类的异同以及具体的使用场景》文章主要介绍了Java中接口(Interface)和抽象类(AbstractClass)的区别和联系,包括相同点和不同点,以及它们在实际开发中的具体使...

Java 中,接口(Interface) 和 抽象类(Abstract Class) 是实现抽象编程的核心机制,二者都用于定义 “规范” 而非完整实现,但在设计理念、语法规则和使用场景上存在显著差异。下面从 异同点核心区别对比具体使用场景 三方面详细解析。

一、接口和抽象类的 “相同点”

二者的核心目标都是 抽象封装共性行为 / 特征,避免代码重复,同时约束子类实现,具体相同点如下:

  1. 都不能实例化:无法通过 new 关键字创建对象(抽象类本质是 “不完整的类”,接口是 “纯规范”,均缺少完整实现)。
  2. 都可包含抽象方法:抽象方法是 “只有声明、没有实现” 的方法(接口中默认抽象,抽象类需显式加 abstract 关键字),子类必须实现所有抽象方法(否则子类仍为抽象类)。
  3. 都用于被继承 / 实现:抽象类通过 extends 被继承,接口通过 implements 被实现,子类 / 实现类需遵循其定义的规范。
  4. 都支持多态:可以声明抽象类 / 接口类型的引用,指向其具体子类 / 实现类的对象(核心体现 “面向接口编程” 思想)。

示例(多态共性):

// 抽象类多态
abstract cfDntwDQglass Animal {}
class Dog extends Animal {}
Animal animal = new Dog(); // 合法
// 接口多态
interface Flyable {}
class Bird implements Flyable {}
Flyable flyable = new Bird(); // 合法

二、接口和抽象类的 “核心区别”

这是重点,需从 语法规则 和 设计理念 两方面区分,下表是全面对比:

对比维度抽象类(Abstract Class)接口(Interface)
继承 / 实现方式子类通过 extends 单继承(Java 不支持多继承)类通过 implements 多实现(可同时实现多个接口)
构造方法可以有构造方法(用于子类初始化时调用 super()不能有构造方法(接口无 “实例状态”,仅定义规范)
成员变量可包含任意成员变量(public/private/protected、静态 / 非静态)只能是 public static final 常量(默认隐式修饰,必须初始化)
成员方法

1. 抽象方法(abstract 修饰);

2. 普通非抽象方法(有方法体);3. JDK8+ 支持默认方法(default)和静态方法(static

1. JDK7-:只能是抽象方法(默认 public abstract);

2. JDK8+:支持默认方法(default)和静态方法(static);

3. JDK9+:支持私有方法(private,用于内部复用)

访问权限成员可声明任意权限(private/protected/public所有成员(方法、常量)默认 public(显式声明也只能是 public
设计理念体现 “is-a” 关系(子类是抽象类的 “一种具体实现”,包含继承的属性和行为)体现 “has-a” 关系(类 “具备” 接口定义的功能,是对行为的补充扩展)
核心作用封装子类的共性属性和行为(既有抽象规范,也有具体实现复用)定义纯行为规范(不关心类的本质,只约束必须实现的功能)
灵活性单继承限制,灵活性低多实现 + 接口继承(extends 多个接口),灵活性高

关键区别详解(避免踩坑)

继承限制:抽象类只能单继承(子类 extends 一个抽象类),接口支持多实现(类 implements A, B)+ 接口多继承(接口 extends A, B)。示例(接口多继承):

interface Runable { void run(); }
interface Flyable { void fly(); }
// 接口可继承多个接口,合并规范
interface SuperAbility extends Runable, Flyable {}
// 类可实现多个接口,实现所有抽象方法
class Superman implements SuperAbility {
    @Override 
    public void run() {}
    @Override 
    public void fly() {}
}

成员变量差异

  • 抽象类的变量可修改(非 final):
    abstract class Person {
        protected String name; // 可被子类修改
        public static int age = 18; // 静态变量可直接访问
    }
    
  • 接口的变量默认是 public static final(必须初始化,不可修改):
    interface Constants {
        String NAME = "phpJava"; // 等价于 public static final String NAME = "Java";
        // int NUM; // 编译报错:必须初始化
    }
    

方法实现差异

抽象类的普通方法可直接被子类复用:

abstract class Vehicle {
    // 具体方法(子类可直接使用,无需重写)
    public void refuel() {
        System.out.println("加油...");
    }
    // 抽象方法(子类必须实现)
    public abstract void drive();
}
class Car extends Vehicle {
    @Override 
    public void drive() { 
        System.out.println("开车..."); 
    }
}
Car car = new Car();
car.refuel(); // 直接复用父类方法,输出“加油...”

接口的默认方法(JDK8+)是为了 “接口升级不破坏原有实现类”,实现类可重写:

interface Greet {
    default void sayHello() {
        System.out.println("Hello");
    }
}
class fDntwDQgChinese implements Greet {
    // 可选重写默认方法
    @Override 
    public void sayHello() {
        System.out.println("你好");
    }
}

三、具体使用场景(核心:选对设计方向)

选择接口还是抽象类,核心看 你要表达的是 “继承关系” 还是 “功能扩展”,以及是否需要复用具体实现。

1. 优先使用抽象类的场景

当你需要定义一个 “类的模板”,子类和父类是 “is-a” 关系,且需要复用 属性或具体方法 时,用抽象类。典型场景:

共性属性 + 行为复用:例如 Animal 抽象类(子类 Dog/Cat 是 “一种动物”),包含 name 属性和 eat() 具体方法(所有动物都要吃饭,实现相同),同时定义 makeSound() 抽象方法(不同动物叫声不同,子类实现)。

abstract class Animal {
    protected String name;
    // 具体方法:复用实现
    public void eat() {
        System.out.println(name + "在吃饭");
    }
    // 抽象方法:约束子类实现
    public abstract void makeSound();
}
class Dog extends Animal {
    pChina编程ublic Dog(String name) {
        this.name = name; 
    }
    @Override 
    public void makeSound() { 
        System.out.println("汪汪叫"); 
    }
}
class Cat extends Animal {
    public Cat(String name) { 
        this.name = name; 
    }
    @Override 
    public void makeSound() { 
        System.out.println("喵喵叫"); 
    }
}
  • 需要构造方法初始化:抽象类的构造方法可用于子类初始化(例如通过 super(name) 给父类属性赋值),接口无构造方法,无法实现。
  • 限制子类数量:单继承特性可避免子类过度扩展(例如 HttpServlet 抽象类,子类只需重写 doGet()/doPost(),无需关注其他 Servlet 生命周期方法)。

2. 优先使用接口的场景

当你需要定义 “功能规范”,类和接口是 “has-a” 关系,且需要 多实现扩展 或 跨类层次复用行为 时,用接口。典型场景:

定义纯行为规范(不关心类的本质):例如 Runnable 接口(只要求类实现 run() js方法,不管是 ThreadTask 还是其他类)、Comparable 接口(只要求类实现比较逻辑)。

// 接口定义“可比较”规范
interface Comparable<T> {
    int compareTo(T o);
}
// 任意类都可实现该接口,获得比较能力(跨类层次复用)
class Student implements Comparable<Student> {
    private int score;
    @Override 
    public int compareTo(Student o) {
        return this.score - o.score;
    }
}
class Product implements Comparable<Product> {
    private double price;
    @Override 
    public int compareTo(Product o) {
        return Double.compare(this.price, o.price);
    }
}
  • 多功能扩展:一个类需要具备多种无关功能时,通过多实现接口实现(例如 Superman 类同时实现 RunableFlyableSwimable 接口,获得跑、飞、游泳三种能力)。
  • 接口回调 / 解耦:例如 Spring 框架的 ApplicationContextAware 接口(实现类可获取 ApplicationContext 对象),框架通过接口规范调用方法,无需关心实现类的具体类型,降低耦合。
  • 接口升级(默认方法):JDK8 后,接口可通过 default 方法添加新功能,而不破坏原有实现类(例如 Collection 接口新增 stream() default 方法,所有集合实现类无需修改即可使用)。

3. 抽象类和接口结合使用(最佳实践)

实际开发中,常结合二者的优势:抽象类提供基础实现,接口定义扩展功能。典型示例:Java 集合框架中的 AbstractCollection(抽象类)和 Collection(接口)。

  • Collection 接口:定义所有集合的核心规范(add()size()iterator() 等抽象方法),不关心实现。
  • AbstractCollection 抽象类:实现 Collection 接口的部分方法(例如 isEmpty()contains()),复用基础逻辑,子类(如 ArrayListLinkedList)只需重写核心方法(add()iterator())即可。

代码简化示例:

// 接口:定义规范
interface Collection {
    boolean add(Object obj);
    int size();
    boolean isEmpty();
}
// 抽象类:实现通用方法,减少子类重复代码
abstract class AbstractCollection implements Collection {
    private int size = 0;
    @Override public boolean add(Object obj) {
        // 子类需实现具体添加逻辑,但size递增可复用
        doAdd(obj);
        size++;
        return true;
    }
    @Override public int size() { return size; }
    @Override public boolean isEmpty() { return size == 0; }
    // 抽象方法:子类必须实现具体添加逻辑
    protected abstract void doAdd(Object obj);
}
// 具体子类:只需关注核心实现
class MyList extends AbstractCollection {
    private Object[] elements = new Object[10];
    @Override protected void doAdd(Object obj) {
        // 实现数组添加逻辑
        for (int i = 0; i < elements.length; i++) {
            if (elements[i] == null) {
                elements[i] = obj;
                break;
            }
        }
    }
}

四、总结(核心选型口诀)

  1. 若子类和父类是 “is-a” 关系,需复用属性或具体方法 → 用 抽象类
  2. 若类需要具备多种无关功能,或定义纯行为规范 → 用 接口
  3. 若需既保证基础实现复用,又支持灵活扩展 → 抽象类 + 接口 结合使用。

本质区别:抽象类是 “类的模板”,侧重继承和复用;接口是 “行为的契约”,侧重规范和扩展。遵循 “面向接口编程” 的设计思想,优先使用接口(解耦、灵活),仅在需要复用具体实现时才用抽象类。

到此这篇关于Java中接口和抽象类的异同以及具体的使用场景的文章就介绍到这了,更多相关java接口和抽象类使用内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Java中接口和抽象类的异同以及具体的使用场景的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1156196

相关文章

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

Java中ArrayList与顺序表示例详解

《Java中ArrayList与顺序表示例详解》顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,:本文主要介绍Java中ArrayList与... 目录前言一、Java集合框架核心接口与分类ArrayList二、顺序表数据结构中的顺序表三、常用代码手动

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

JAVA线程的周期及调度机制详解

《JAVA线程的周期及调度机制详解》Java线程的生命周期包括NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED,线程调度依赖操作系统,采用抢占... 目录Java线程的生命周期线程状态转换示例代码JAVA线程调度机制优先级设置示例注意事项JAVA线程

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位