Skip to content
第 22 / 250 章后端⏱ 10 分钟阅读

第 22 章:内部类与枚举

学习目标

  • 掌握四种内部类的用法
  • 理解枚举的本质和高级用法

一、为什么需要内部类?

内部类 = 定义在另一个类内部的类,用于逻辑分组和封装。

java
public class Outer {
    private String outerField = "外部";

    public class Inner {                  // ① 成员内部类
        public void hello() {
            System.out.println(outerField);  // ✅ 直接访问外部类私有字段
        }
    }
}

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();    // ② 创建内部类需要外部实例
inner.hello();

二、四种内部类

2.1 成员内部类

java
public class Outer {
    private int x = 10;

    public class Inner {
        private int y = 20;

        public void print() {
            System.out.println("外部 x = " + x);    // ① 访问外部类
            System.out.println("内部 y = " + y);
        }
    }
}

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();  // ① 依赖外部实例
inner.print();

2.2 静态内部类

java
public class Outer {
    private static int x = 10;        // ① 静态字段

    public static class Inner {        // ② 静态内部类
        public void hello() {
            System.out.println("静态 x = " + x);  // ③ 只能访问静态成员
        }
    }
}

Outer.Inner inner = new Outer.Inner();  // ✅ 不需要外部实例
inner.hello();

2.3 局部内部类

java
public class Outer {
    public void method() {
        int localVar = 10;

        class LocalInner {            // ① 定义在方法内
            public void print() {
                System.out.println(localVar);  // ② 只能访问 effectively final
            }
        }

        new LocalInner().print();
    }
}

2.4 匿名内部类(Lambda 的前身)

java
// 传统匿名内部类
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("hello");
    }
};

// ✅ Lambda(JDK 8+,推荐)
Runnable r2 = () -> System.out.println("hello");

三、枚举的本质

枚举特殊的类,所有实例在编译时就确定:

java
public enum OrderStatus {
    PENDING,    // ① 枚举值(隐式 public static final)
    PAID,
    SHIPPED,
    DELIVERED,
    CANCELLED;
}
java
OrderStatus status = OrderStatus.PAID;
System.out.println(status.name());        // "PAID"
System.out.println(status.ordinal());    // 1(顺序)

// 遍历所有枚举值
for (OrderStatus s : OrderStatus.values()) {
    System.out.println(s);
}

四、枚举的高级用法

4.1 枚举 + 字段 + 方法

java
public enum OrderStatus {
    PENDING("待支付"),
    PAID("已支付"),
    SHIPPED("已发货"),
    DELIVERED("已签收"),
    CANCELLED("已取消");

    private final String description;     // ① 字段

    OrderStatus(String description) {     // ② 构造器(默认 private)
        this.description = description;
    }

    public String getDescription() {      // ③ 方法
        return description;
    }

    public boolean canCancel() {          // ④ 业务方法
        return this == PENDING || this == PAID;
    }
}

4.2 枚举 + switch

java
public String handle(OrderStatus status) {
    return switch (status) {
        case PENDING -> "订单待支付";
        case PAID -> "订单已支付";
        case SHIPPED -> "订单已发货";
        case DELIVERED -> "订单已签收";
        case CANCELLED -> "订单已取消";
    };
}

4.3 枚举实现接口

java
public interface Describable {
    String describe();
}

public enum OrderStatus implements Describable {
    PENDING {                               // ① 每个枚举值可以独立实现
        public String describe() {
            return "待支付";
        }
    },
    PAID {
        public String describe() {
            return "已支付";
        }
    };
}

五、枚举 vs 常量类

java
// ❌ 常量类(不推荐)
public class OrderStatusConst {
    public static final int PENDING = 1;
    public static final int PAID = 2;
    // 没有类型安全,没有命名空间
}

// ✅ 枚举(推荐)
public enum OrderStatus {
    PENDING, PAID, SHIPPED;
    // 类型安全 + 命名空间 + 内置方法
}

六、本章小结

要点关键
成员内部类依赖外部实例
静态内部类不依赖外部实例
局部内部类在方法 / 块内
匿名内部类一次性使用,Lambda 替代
枚举有限个数的常量集,类型安全
枚举高级用法字段、方法、switch、接口

动手练习

练习 1:基础题

定义枚举 Color(RED, GREEN, BLUE),给每个枚举添加 RGB 值字段。

练习 2:进阶题

定义枚举 Operation(PLUS, MINUS, MULTIPLY, DIVIDE),实现方法 apply(int a, int b) 计算结果。


下一章第 23 章:Object 类

本站基于 VitePress 构建 · 由 Codebook 团队维护