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

Java抽象/接口讲解(第五节)抽象类和接口的区别

抽象类和接口是 Java 中实现抽象多态的重要工具,它们在设计上有相似之处(都可以用于定义行为规范),但在功能、实现方式和应用场景上存在显著区别。理解这两者的区别对于编写灵活且易维护的代码至关重要。

1. 概念区别

抽象类
  • 抽象类是一个类,不能被直接实例化,用于定义子类的通用属性和行为。抽象类可以包含抽象方法(没有方法体,需要子类实现)和具体方法(已经实现的)。
  • 应用场景:当你希望为一组类提供通用的功能,同时允许子类共享这些通用功能时,可以使用抽象类。
接口
  • 接口是一个完全抽象的类型,它定义了一组行为规范,而不提供任何实现(Java 8 之后接口可以包含默认实现)。实现接口的类必须实现接口中的所有方法。
  • 应用场景:当你希望定义一组行为,而不关心这些行为的具体实现时,使用接口。接口主要用于多继承场景或定义类的能力。

2. 语法和结构的区别

特性抽象类接口
关键字abstract classinterface
方法可以包含抽象方法具体方法只能包含抽象方法(Java 8 之前),可以有默认方法静态方法
成员变量可以有成员变量(实例变量)只能有常量,即 public static final 变量
构造方法可以有构造方法不能有构造方法
访问修饰符方法和变量可以是 publicprotectedprivate方法默认是 public abstract,变量是 public static final
继承一个类只能继承一个抽象类一个类可以实现多个接口
实现继承要求子类可以选择实现抽象类中的部分方法类必须实现接口中的所有方法

3. 抽象类与接口的特性对比

3.1 方法定义
  • 抽象类:可以有抽象方法(需要子类实现)和具体方法(已经有方法体的实现)。
  • 接口:Java 8 之前,接口中的所有方法都是抽象方法。Java 8 之后,接口可以包含默认方法default,有方法体的具体实现)和静态方法

抽象类示例

abstract class Animal {
    public abstract void makeSound();  // 抽象方法

    public void sleep() {  // 具体方法
        System.out.println("动物正在睡觉");
    }
}

接口示例

interface Runnable {
    void run();  // 抽象方法 (默认是 public abstract)
    
    default void stop() {  // Java 8 之后的默认方法
        System.out.println("停止运行");
    }
}
3.2 成员变量
  • 抽象类:可以有成员变量(实例变量),子类可以继承和使用。
  • 接口:只能有常量,即 public static final 变量,所有变量必须在定义时初始化。

抽象类示例

abstract class Animal {
    protected String name;  // 成员变量
}

接口示例

interface Flyable {
    int MAX_HEIGHT = 1000;  // 常量,隐式地 public static final
}
3.3 构造方法
  • 抽象类:可以有构造方法,用于初始化父类的成员变量。尽管抽象类不能实例化,但子类创建对象时可以调用抽象类的构造方法。
  • 接口:不能有构造方法,因为接口本质上不是类,不能被实例化。

抽象类示例

abstract class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;  // 初始化成员变量
    }
}

4. 继承与实现的区别

4.1 单继承 vs 多继承
  • 抽象类:类与类之间是单继承的,一个类只能继承一个抽象类(或者普通类),不能继承多个类。
  • 接口:一个类可以实现多个接口,接口提供了多继承的效果,允许类同时拥有多个行为。

示例:单继承

abstract class Animal {
    public abstract void makeSound();
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("狗在叫");
    }
}
示例:多接口实现
interface Runnable {
    void run();
}

interface Swimmable {
    void swim();
}

class Frog implements Runnable, Swimmable {  // 同时实现两个接口
    @Override
    public void run() {
        System.out.println("青蛙在跑");
    }

    @Override
    public void swim() {
        System.out.println("青蛙在游泳");
    }
}
4.2 实现要求
  • 抽象类:子类可以选择实现部分或全部抽象类中的方法。如果不实现全部方法,子类仍然是抽象类。
  • 接口:实现接口的类必须实现接口中的所有抽象方法。否则,类必须声明为抽象类。

5. 应用场景的区别

5.1 抽象类的使用场景
  • 当类之间有共性且需要共享一些实现时,可以使用抽象类。抽象类允许提供通用的功能,子类只需要重写特定的行为。
  • 抽象类可以拥有成员变量,因此适合需要保存状态的场景(比如拥有共享数据的类)。

示例:通用功能的抽象类

abstract class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void sleep() {
        System.out.println(name + " 正在睡觉");
    }

    public abstract void makeSound();
}

class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " 在汪汪叫");
    }
}
5.2 接口的使用场景
  • 接口适用于为类提供某种能力行为,并且这些类可能来自不同的继承体系。例如,一个类可能需要实现多个不相关的接口,从而同时具备多个行为。
  • 接口更倾向于定义一种能力,而不是对象之间的继承关系。例如,一个类可以实现 Flyable 接口表示它可以飞,或者实现 Swimmable 接口表示它可以游泳。

示例:定义能力的接口

interface Flyable {
    void fly();
}

interface Swimmable {
    void swim();
}

class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("鸭子在飞");
    }

    @Override
    public void swim() {
        System.out.println("鸭子在游泳");
    }
}

6. Java 8 引入的新特性

Java 8 之后,接口引入了一些新特性,模糊了接口和抽象类的部分边界。

6.1 默认方法(Default Method)
  • 接口可以有默认方法,即 default 方法,允许接口在不破坏已有实现类的情况下扩展新的功能。默认方法提供了一个方法的默认实现,实现类可以选择重写它。
    interface Runnable {
        void run();
    
        default void stop() {  // Java 8 中的新特性
            System.out.println("停止运行");
        }
    }
    
6.2 静态方法(Static Method)
  • 接口可以有静态方法,静态方法可以直接通过接口名调用,而不需要实现类的实例。静态方法不能被实现类重写。
interface Flyable {
    static void checkWind() {
        System.out.println("检查风速");
    }
}

7. 总结

特性抽象类接口
定义用于定义类之间的共性,可以包含具体方法和抽象方法完全抽象的类型,只定义行为规范,不提供实现(Java 8 后可以有默认实现)
方法可以包含具体方法和抽象方法只能包含抽象方法,Java 8 之后可以有默认方法和静态方法
成员变量可以包含实例变量只能包含 public static final 常量
构造方法可以有构造方法,用于初始化类的状态不能有构造方法,因为接口不能实例化
继承和实现一个类只能继承一个抽象类一个类可以实现多个接口
应用场景用于为一组相关类提供通用功能用于为类提供能力或行为规范,适用于多继承或无关类之间共享行为
使用抽象类的场景
  • 当类之间有明确的继承关系,且需要共享部分实现时使用抽象类。
使用接口的场景
  • 当需要定义一组行为,且类可以来自不同的继承体系时使用接口。接口非常适合为类定义能力或行为规范。

http://www.kler.cn/a/308039.html

相关文章:

  • docker:docker: Get https://registry-1.docker.io/v2/: net/http: request canceled
  • 远离生成式AI大乱斗,SAS公司揭示亚太区千亿AI市场蓝图
  • WebSocket和HTTP协议的性能比较与选择
  • Fastapi使用MongoDB作为数据库
  • 数据库SQL——连接表达式(JOIN)图解
  • three.js 杂记
  • 【C++】——继承详解
  • oracle 用游标为什么会比for循环慢?
  • 说说“天上一天地上一年”该怎么理解
  • Golang | Leetcode Golang题解之第404题左叶子之和
  • 递归10小题
  • BSN六周年:迈向下一代互联网
  • 『功能项目』制作提示主角升级面板【56】
  • AI时代个人发展
  • MATLAB、FPGA、STM32中调用FFT计算频率、幅值及相位差
  • 深度学习----------------------文本预处理
  • 进阶SpringBoot之异步任务、邮件任务和定时执行任务
  • 2024最新版MySQL详细学习教程
  • 算法两道题
  • PyCharm 安装
  • 【重学 MySQL】二十八、SQL99语法新特性之自然连接和 using 连接
  • 无人机在战争方面的应用!!!
  • 计算机毕业设计 基于协同过滤算法的个性化音乐推荐系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • unity3d入门教程七
  • 如何编写智能合约——基于长安链的Go语言的合约开发
  • 我想要抓取新加坡当地电商平台数据,使用什么地区的IP最合适