内部类与嵌套类型
约 1030 字大约 3 分钟
布欧-Lewyon
2026-05-16
Java 允许在一个类内部定义另一个类,称为嵌套类。根据是否有 static 修饰,分为静态嵌套类和内部类(非静态嵌套类)。理解它们的作用域、实例化方式和与外部类的关系,是阅读框架源码和编写事件驱动代码的基础。
分类一览
嵌套类
├── 静态嵌套类(static nested class) — 独立于外部类实例
└── 内部类(inner class / 非静态)
├── 成员内部类 — 普通内部类,持有外部类引用
├── 局部内部类 — 定义在方法内
└── 匿名内部类 — 定义在表达式内,无类名静态嵌套类
用 static 修饰的嵌套类,逻辑上属于外部类,但不持有外部类实例的引用,可独立创建:
public class Outer {
private static String staticField = "静态字段";
public static class StaticNested {
public void print() {
System.out.println(staticField); // 可访问外部类的静态成员
}
}
}
// 使用:无需外部类实例
Outer.StaticNested nested = new Outer.StaticNested();
nested.print();典型应用:Map.Entry 接口的内部实现 Node、建造者模式中的 Builder 类。
成员内部类
非 static 的嵌套类,隐式持有外部类实例的引用,可访问外部类的所有成员(包括 private):
public class Outer {
private String message = "Hello";
public class Inner {
public void print() {
System.out.println(message); // 可访问外部类的私有字段
}
}
public Inner createInner() {
return new Inner();
}
}
// 使用:必须通过外部类实例
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 或 outer.createInner()
inner.print();- 成员内部类中不能定义
static成员(非常量)。 - 如果外部类与内部类有同名成员,用
Outer.this.成员区分。
局部内部类
定义在方法体内部的类,作用域仅限该方法:
public class Outer {
public void process() {
class LocalInner {
private String name;
LocalInner(String name) { this.name = name; }
void show() {
System.out.println(name);
}
}
LocalInner li = new LocalInner("test");
li.show();
}
}局部内部类可以访问外部类的成员以及所在方法的 final 或 effectively final 局部变量。
匿名内部类
定义在表达式内的无类名内部类,常用于一次性的接口实现或事件监听。Lambda 表达式的"前身":
// 匿名内部类实现 Runnable
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
// 等价 Lambda
Runnable task2 = () -> System.out.println("Lambda");Lambda 本质上就是对函数式接口的匿名内部类的语法糖。
匿名内部类 vs Lambda 的关键区别
| 特性 | 匿名内部类 | Lambda |
|---|---|---|
this 指向 | 匿名类自身 | 外部类(这一点最易错) |
| 适用范围 | 任何接口/类(无论有无抽象方法数) | 仅函数式接口(单抽象方法) |
| 字节码 | 生成独立 .class 文件 | invokedynamic,更轻量 |
嵌套类的实际用途
// 1. 迭代器模式 —— ArrayList.Itr 是成员内部类,持有外部 ArrayList 引用
public class ArrayList<E> {
private class Itr implements Iterator<E> {
int cursor;
public E next() { /* 访问 ArrayList 的 elementData */ }
}
}
// 2. 建造者模式 —— 静态嵌套类
public class User {
private final String name;
private final int age;
public static class Builder {
private String name;
private int age;
public Builder name(String n) { this.name = n; return this; }
public Builder age(int a) { this.age = a; return this; }
public User build() { return new User(name, age); }
}
private User(String name, int age) { this.name = name; this.age = age; }
}小结
- 嵌套类分两类:
static(不持有外部引用)和内部类(隐式持有外部引用)。 - 成员内部类通过
外部类实例.new 内部类()创建,可访问外部类的private成员。 - 匿名内部类被 Lambda 替代是趋势,但注意
this指向不同。 - 框架源码大量使用嵌套类:
ArrayList.Itr、HashMap.Node、Stream中的各类Sink实现。 - 易错:内部类持有外部类引用会阻止外部类被 GC——如果内部类生命周期比外部类长,可能导致内存泄漏(如 Android 中 Activity 销毁后 Handler 内部类仍持有引用)。
- 思考任务:用静态嵌套类实现一个
ConfigBuilder,支持链式调用设置属性,最后调用build()返回不可变的Config对象。
上一节:面向对象基础
下一节:继承与多态
