JavaWeb 30 天入门:第六天 —— 抽象类与接口 - 指南

        在前五天的学习中,我们掌握了 Java 基础语法、数组、方法以及面向对象的核心特性(封装、继承、多态)。今天我们将学习面向对象中的两个重要概念 ——抽象类接口。它们是实现多态的重要载体,也是 JavaWeb 开发中框架设计的基础(如 Servlet 接口、Spring 中的各种接口)。理解抽象类和接口的区别与应用场景,能帮助我们写出更具扩展性的代码。

抽象类:不完整的类

什么是抽象类?

在面向对象中,有些类只作为父类被继承,而不会被实例化(创建对象),这类类称为抽象类。抽象类中可以包含普通方法和抽象方法(只有方法声明,没有方法实现)。

例如:"图形" 类(Shape)是一个抽象概念,它的 "计算面积" 方法无法具体实现(不同图形面积计算方式不同),因此可以定义为抽象类。

抽象类的定义

使用abstract关键字定义抽象类和抽象方法:

// 抽象类
public abstract class 类名 {
// 普通属性
属性类型 属性名;
// 普通方法(有实现)
修饰符 返回值类型 方法名() {
// 方法体
}
// 抽象方法(没有实现,必须以分号结尾)
public abstract 返回值类型 抽象方法名(参数列表);
}

抽象类的特点

  1. 不能实例化:抽象类无法通过new关键字创建对象

    // 错误示例
    Shape s = new Shape(); // 编译报错:Shape是抽象类,不能实例化
  2. 必须被继承:抽象类的子类必须重写所有抽象方法(除非子类也是抽象类)

  3. 可以包含普通成员:抽象类可以有普通属性、普通方法、构造方法(供子类调用)

抽象类实例:图形类体系

// 抽象父类:图形
public abstract class Shape {
// 普通属性
protected String color;
// 构造方法
public Shape(String color) {
this.color = color;
}
// 普通方法
public String getColor() {
return color;
}
// 抽象方法:计算面积(无法具体实现)
public abstract double calculateArea();
// 抽象方法:获取图形名称
public abstract String getShapeName();
}
// 子类:圆形(必须重写所有抽象方法)
public class Circle extends Shape {
private double radius; // 半径
public Circle(String color, double radius) {
super(color); // 调用父类构造
this.radius = radius;
}
// 重写抽象方法:计算面积
@Override
public double calculateArea() {
return Math.PI * radius * radius; // 圆面积公式:πr²
}
// 重写抽象方法:获取图形名称
@Override
public String getShapeName() {
return "圆形";
}
}
// 子类:矩形
public class Rectangle extends Shape {
private double length; // 长
private double width;  // 宽
public Rectangle(String color, double length, double width) {
super(color);
this.length = length;
this.width = width;
}
@Override
public double calculateArea() {
return length * width; // 矩形面积公式:长×宽
}
@Override
public String getShapeName() {
return "矩形";
}
}
// 测试类
public class TestShape {
public static void main(String[] args) {
// 多态:抽象类引用指向子类对象
Shape circle = new Circle("红色", 5.0);
Shape rectangle = new Rectangle("蓝色", 4.0, 6.0);
// 调用抽象方法(实际执行子类实现)
System.out.println(circle.getShapeName() + "面积:" + circle.calculateArea());
System.out.println(rectangle.getShapeName() + "面积:" + rectangle.calculateArea());
}
}

运行结果:

圆形面积:78.53981633974483
矩形面积:24.0

抽象类的应用场景

  1. 抽取共性但无法具体实现的方法:当多个子类有共同方法但实现不同时,将方法声明为抽象方法
  2. 作为模板类:定义一套规范,强制子类实现特定方法(如 Java 中的InputStream抽象类)
  3. 限制实例化:确保某些类只能作为父类使用(如框架中的基础类)

接口:行为规范

什么是接口?

接口(Interface)是一种完全抽象的类型,它只定义方法的声明(在 Java 8 + 中可以有默认方法和静态方法),不包含属性的实现(变量默认是public static final)。

接口的本质是行为规范,它规定了一个类应该具有哪些方法,但不关心方法的具体实现。例如:"飞行" 接口可以规定fly()方法,鸟、飞机等类都可以实现这个接口。

接口的定义与实现

使用interface关键字定义接口,使用implements关键字实现接口:

// 定义接口
public interface 接口名 {
// 常量(默认public static final)
数据类型 常量名 = 值;
// 抽象方法(默认public abstract)
返回值类型 方法名(参数列表);
// Java 8+:默认方法(有实现,用default修饰)
default 返回值类型 方法名() {
// 方法体
}
// Java 8+:静态方法(有实现)
static 返回值类型 方法名() {
// 方法体
}
}
// 实现接口
public class 类名 implements 接口名1, 接口名2 {
// 必须重写所有接口的抽象方法
@Override
public 返回值类型 方法名(参数列表) {
// 实现
}
}

接口的特点

  1. 不能实例化:接口无法创建对象
  2. 多实现:一个类可以实现多个接口(弥补 Java 单继承的不足)
  3. 接口继承接口:接口可以通过extends继承多个接口
  4. 方法默认修饰符:抽象方法默认public abstract,变量默认public static final

接口实例:行为规范

// 接口1:飞行行为
public interface Flyable {
// 抽象方法:飞行
void fly();
// 默认方法:起飞
default void takeOff() {
System.out.println("准备起飞...");
}
// 静态方法:获取飞行高度单位
static String getHeightUnit() {
return "米";
}
}
// 接口2:游泳行为
public interface Swimmable {
void swim();
}
// 类实现多个接口:鸭子(会飞也会游泳)
public class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("鸭子在低空飞行");
}
@Override
public void swim() {
System.out.println("鸭子在水面游弋");
}
}
// 类实现单个接口:鱼(只会游泳)
public class Fish implements Swimmable {
@Override
public void swim() {
System.out.println("鱼在水中游动");
}
}
// 测试类
public class TestInterface {
public static void main(String[] args) {
Duck duck = new Duck();
duck.takeOff(); // 调用接口的默认方法
duck.fly();
duck.swim();
Fish fish = new Fish();
fish.swim();
// 调用接口的静态方法
System.out.println("飞行高度单位:" + Flyable.getHeightUnit());
}
}

运行结果:

准备起飞...
鸭子在低空飞行
鸭子在水面游弋
鱼在水中游动
飞行高度单位:米

接口的应用场景

  1. 定义行为规范:如 Java 中的Runnable(线程运行)、Comparable(比较)接口
  2. 实现多继承效果:一个类可以实现多个接口,拥有多种行为能力
  3. 解耦设计:接口作为标准,实现类可以灵活替换(如 JavaWeb 中的Servlet接口)
  4. 回调机制:通过接口实现回调功能(如事件监听)

抽象类与接口的区别

特性抽象类(Abstract Class)接口(Interface)
关键字abstract classinterface
继承 / 实现方式子类用extends继承类用implements实现
继承数量单继承(一个类只能继承一个抽象类)多实现(一个类可实现多个接口)
方法实现可以有普通方法(有实现)和抽象方法抽象方法无实现;Java8 + 可有默认方法和静态方法
属性可以有各种修饰符的属性属性默认是public static final(常量)
构造方法有构造方法(供子类调用)没有构造方法
设计理念体现 "is-a" 关系(继承体系)体现 "has-a" 关系(行为规范)

如何选择抽象类和接口?

  • 用抽象类:当需要定义一个类的基本结构(属性 + 方法),且部分方法可以实现时
  • 用接口:当需要定义一组行为规范,且不关心具体实现时
  • 两者结合:一个类可以继承抽象类的同时实现多个接口(如ArrayList继承AbstractList并实现List接口)

接口在 JavaWeb 中的典型应用

  1. Servlet 接口

    // 所有Servlet都必须实现的接口
    public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    void destroy();
    // ...其他方法
    }
  2. 过滤器接口(Filter)

    public interface Filter {
    void init(FilterConfig filterConfig) throws ServletException;
    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException;
    void destroy();
    }

这些接口定义了组件的基本行为规范,具体实现由开发者或框架提供,体现了接口的解耦优势。

总结与实践

知识点回顾

  1. 抽象类

    • abstract关键字定义,包含普通方法和抽象方法
    • 不能实例化,必须被继承,子类需重写所有抽象方法
    • 适合作为有共性但无法完全实现的父类
  2. 接口

    • interface关键字定义,主要包含抽象方法(Java8 + 支持默认方法和静态方法)
    • 类通过implements实现接口,可多实现
    • 适合定义行为规范,实现多态和解耦
  3. 核心区别:抽象类体现继承关系,接口体现行为规范;抽象类单继承,接口多实现。

实践任务

  1. 创建支付系统接口

    • 定义Payment接口,包含抽象方法pay(double amount)(支付)和refund(double amount)(退款)
    • 定义WechatPayAlipay两个类,实现Payment接口
    • 在实现类中分别实现微信支付和支付宝支付的具体逻辑(打印支付 / 退款信息即可)
    • 创建测试类,用多态方式调用支付和退款功能
  2. 扩展任务

    • 创建AbstractPayment抽象类,实现Payment接口,添加getPaymentName()普通方法
    • WechatPayAlipay继承AbstractPayment,重写getPaymentName()方法
    • 体会抽象类和接口结合使用的优势

思考:在实际开发中,为什么框架(如 Spring)大量使用接口而不是抽象类?

posted @ 2025-08-12 10:51  yfceshi  阅读(5)  评论(0)    收藏  举报