面向对象_抽象类与接口

抽象类(abstract class)

抽象类是 Java 中一种特殊的类,用 abstract 关键字修饰,它不能被实例化,主要用于作为其他类的父类,提取 子类的共性并定义规范。

抽象类的核心特性

  1. 不能实例化

抽象类无法直接创建对象(new AbstractClass() 会编译报错),必须通过子类继承并实现所有抽象方法后,才能实例化子类对象。

java 复制代码
abstract class Shape { ... }
// Shape shape = new Shape(); // 错误:抽象类不能实例化
  1. 可包含抽象方法和普通方法
  • 抽象方法:用 abstract 修饰,只有方法声明(无方法体),必须由子类强制重写。

语法:abstract 返回值类型 方法名(参数列表);

  • 普通方法:有完整的方法体(实现逻辑),子类可直接继承使用,也可选择重写。
  1. 可包含成员变量和构造方法
  • 成员变量:可使用任意访问修饰符(private/protected/public 等),子类可通过继承或 getter 访问。
  • 构造方法:抽象类有构造方法(用于子类初始化时调用),但不能直接用于实例化自身。

抽象类的定义与使用示例

java 复制代码
public class AbstractDemo {
    public static void main(String[] args) {
        // 通过子类实例化(抽象类本身不能实例化)
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(4, 6);

        System.out.println("圆的面积:" + circle.calculateArea()); // 78.5
        System.out.println("矩形的面积:" + rectangle.calculateArea()); // 24
        circle.display(); // 输出:这是一个图形
    }
}

// 抽象类:定义图形的共性
abstract class Shape {
    // 成员变量
    protected String color;

    // 构造方法(供子类调用)
    public Shape() {
        this.color = "白色";
    }

    // 抽象方法(必须由子类实现):计算面积
    public abstract double calculateArea();

    // 普通方法(有实现):显示图形信息
    public void display() {
        System.out.println("这是一个图形,颜色:" + color);
    }
}

// 子类1:圆形(继承抽象类并实现抽象方法)
class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    // 实现抽象方法:计算圆面积
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

// 子类2:矩形(继承抽象类并实现抽象方法)
class Rectangle extends Shape {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    // 实现抽象方法:计算矩形面积
    @Override
    public double calculateArea() {
        return length * width;
    }
}

抽象类的作用

  1. 提取共性,实现代码复用

将多个子类的共同属性(如 color)和方法(如 display())定义在抽象类中,子类无需重复编写。

  1. 定义规范,强制子类实现

抽象方法(如 calculateArea())规定了子类必须具备的功能,但不限制具体实现(圆和矩形的面积计算方式不同),既保证了一致性,又保留了灵活性。

  1. 作为多态的载体

抽象类的引用可以指向任意子类对象(向上转型),实现 "同一接口,不同实现" 的多态效果(如示例中用 Shape 引用分别指向 CircleRectangle)。

使用注意事项

  • 抽象类中可以没有抽象方法(全是普通方法),但此时仍不能实例化,通常用于禁止直接创建对象。
  • 子类继承抽象类后,必须重写所有抽象方法,否则子类也必须声明为抽象类(层层传递,直到某个子类完全实现)。
  • 抽象类不能用 final 修饰(final 类不能被继承,与抽象类的设计目的冲突)。

接口

接口(interface)是 Java 中定义行为规范的重要机制,它专注于描述 "能做什么 ",而不关心 "如何做"。

接口的核心组成(Java 8+)

接口可以包含常量抽象方法默认方法静态方法,具体规则如下:

常量定义

接口中的变量默认被 public static final 修饰(可省略),必须初始化且不可修改,本质是全局常量。

语法:[public static final] 数据类型 常量名 = 值;

示例:

java 复制代码
interface MathConstants {
    double PI = 3.1415926; // 等价于 public static final double PI = ...
    int MAX_VALUE = 1000;  // 全局常量
}

抽象方法(核心)

接口中的抽象方法默认被 public abstract 修饰(可省略),只有方法声明,无方法体,必须由实现类实现。

语法:[public abstract] 返回值类型 方法名(参数列表);

示例:

java 复制代码
interface Flyable {
    void fly(); // 等价于 public abstract void fly();
    void land(); // 抽象方法,需实现类重写
}

默认方法(Java 8 新增)

default 修饰,有方法体,供实现类直接使用或重写,解决接口升级时的兼容性问题(无需修改所有实现类)。

语法:public default 返回值类型 方法名(参数列表) { ... }

示例:

java 复制代码
interface Flyable {
    void fly();
    
    // 默认方法(有实现)
    default void prepare() {
        System.out.println("准备飞行");
    }
}

// 实现类可直接使用默认方法
class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟飞行");
    }
    // 未重写prepare(),使用接口默认实现
}

// 实现类也可重写默认方法
class Plane implements Flyable {
    @Override
    public void fly() {
        System.out.println("飞机飞行");
    }
    
    @Override
    public void prepare() {
        System.out.println("飞机检查设备,准备飞行"); // 重写默认方法
    }
}

静态方法(Java 8 新增)

static 修饰,有方法体,属于接口本身,只能通过接口名调用,实现类不能重写。

语法:public static 返回值类型 方法名(参数列表) { ... }

示例:

java 复制代码
interface Flyable {
    void fly();
    
    // 静态方法
    static void showInfo() {
        System.out.println("这是飞行接口");
    }
}

// 调用静态方法
public class Test {
    public static void main(String[] args) {
        Flyable.showInfo(); // 正确:通过接口名调用
        // Bird.showInfo(); // 错误:实现类不能调用接口的静态方法
    }
}

接口的使用规则

  1. 实现接口 :类通过 implements 关键字实现接口,需重写所有抽象方法(默认方法和静态方法可选重写 / 使用)。
java 复制代码
class Bird implements Flyable {
    @Override
    public void fly() { ... } // 必须重写抽象方法
}
  1. 多实现:一个类可以实现多个接口(用逗号分隔),弥补 Java 单继承的限制。
java 复制代码
interface Flyable { void fly(); }
interface Swimmable { void swim(); }

// 同时实现两个接口
class Duck implements Flyable, Swimmable {
    @Override public void fly() { ... }
    @Override public void swim() { ... }
}
  1. 接口继承接口:接口可以通过 extends 继承其他接口(支持多继承),子接口包含父接口的所有成员。
java 复制代码
interface Moveable { void move(); }
interface Flyable extends Moveable { void fly(); } // 继承Moveable

// 实现子接口需重写所有抽象方法(包括父接口的)
class Plane implements Flyable {
    @Override public void move() { ... }
    @Override public void fly() { ... }
}
  1. 不能实例化:接口无法直接创建对象,必须通过实现类实例化,且接口引用可指向实现类对象(多态)。
java 复制代码
Flyable flyable = new Bird(); // 接口引用指向实现类对象(多态)

接口的典型应用场景

  1. 定义规范 :作为系统模块或组件的 "契约",明确必须实现的功能(如 Runnable 接口规定线程任务)。
  2. 多态基础 :通过接口引用实现 "同一接口,不同实现"(如 List 接口有 ArrayListLinkedList 等实现)。
  3. 功能扩展 :为类添加额外能力(无继承关系的类可实现同一接口,如 BirdPlane 都实现 Flyable)。

区别与应用场景

核心区别(语法与特性)

对比维度 抽象类( **abstract class** 接口( **interface**
定义关键字 abstract class interface
继承 / 实现方式 子类用 extends 继承(单继承,一个类只能继承一个抽象类) 类用 implements 实现(多实现,一个类可实现多个接口)
成员变量 可包含任意修饰符的变量(private/protected/public等,可修改) 只能是 public static final 常量(必须初始化,不可修改)
方法类型 + 抽象方法(abstract,无实现) + 普通方法(有实现) + 静态方法(static + 抽象方法(默认 public abstract) + 默认方法(default,有实现) + 静态方法(static,有实现)
构造方法 有构造方法(供子类初始化时调用) 无构造方法
实例化 不能直接实例化,需子类实现所有抽象方法后实例化子类 不能直接实例化,需实现类实现所有抽象方法后实例化实现类
设计意图 表示 "is-a" 关系(强调继承,描述 "是什么") 表示 "has-a" 关系(强调功能,描述 "能做什么")

应用场景选择

  1. 优先使用抽象类的场景
  • 提取子类共性属性和方法 :当多个子类存在共同的属性(如 nameage)和已实现的方法(如 eat())时,抽象类可作为 "模板" 统一管理这些共性,避免重复代码。

示例:

定义 Animal 抽象类,包含所有动物共有的 name 属性和 sleep() 方法,子类(DogCat)只需实现各自的 makeSound()抽象方法。

  • 类之间存在明确的 " **is-a**" 继承关系:当子类是父类的 "一种具体类型" 时,适合用抽象类。

示例:Student is a PersonCar is a Vehicle,此时 PersonVehicle 适合作为抽象类。

  • 需要定义非抽象方法:当多个子类需要复用相同的方法实现(而非重复编写)时,抽象类的普通方法可以满足这一需求。
  1. 优先使用接口的场景
  • 定义跨类别的功能规范:当不同类(无继承关系)需要具备相同的行为时,接口可作为 "功能契约"。

示例:BirdPlaneInsect 无继承关系,但都能 "飞行",可通过 Flyable 接口定义 fly() 方法。

  • 需要多实现能力:Java 不支持类的多继承,但一个类可实现多个接口,从而拥有多种功能。

示例:Duck 可同时实现 Swimmable(游泳)和 Flyable(飞行)接口,表明它 "既能游又能飞"。

  • 框架或 API 的规范定义:接口常用于定义模块间的交互标准(如回调接口、监听器),实现 "依赖倒置"(依赖抽象而非具体实现)。

示例:Runnable 接口定义线程任务的规范,List 接口定义集合的通用操作。

  • 接口升级兼容 :Java 8+ 的默认方法(default)允许在接口中添加新方法而不影响现有实现类,适合接口的迭代升级。
相关推荐
RainbowSea5 分钟前
1. LangChain4J 理论概述
java·langchain·llm
刘 大 望28 分钟前
网络编程--TCP/UDP Socket套接字
java·运维·服务器·网络·数据结构·java-ee·intellij-idea
没有bug.的程序员41 分钟前
AOT 编译与 GraalVM 实战:Java 云原生的终极进化
java·python·云原生·graalvm·aot
找不到、了1 小时前
常用的分布式ID设计方案
java·分布式
野区捕龙为宠1 小时前
Unity Netcode for GameObjects(多人联机小Demo)
java·unity·游戏引擎
十八旬2 小时前
苍穹外卖项目实战(日记十)-记录实战教程及问题的解决方法-(day3-2)新增菜品功能完整版
java·开发语言·spring boot·mysql·idea·苍穹外卖
鞋尖的灰尘2 小时前
springboot-事务
java·后端
银迢迢2 小时前
SpringCloud微服务技术自用笔记
java·spring cloud·微服务·gateway·sentinel
用户0332126663672 小时前
Java 将 CSV 转换为 Excel:告别繁琐,拥抱高效数据处理
java·excel
这周也會开心2 小时前
Java-多态
java·开发语言