面向对象_抽象类与接口

抽象类(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)允许在接口中添加新方法而不影响现有实现类,适合接口的迭代升级。
相关推荐
考虑考虑3 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261354 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊5 小时前
Java学习第22天 - 云原生与容器化
java
渣哥7 小时前
原来 Java 里线程安全集合有这么多种
java
间彧7 小时前
Spring Boot集成Spring Security完整指南
java
间彧7 小时前
Spring Secutiy基本原理及工作流程
java
Java水解8 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆10 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学11 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole11 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端