成员内部类依附外部类实例,可访问其所有成员(含私有及静态),创建需先有外部类对象,如new outer().new inner();不能定义普通静态成员,jdk 16起允许static final常量。

成员内部类:依附外部实例,访问无限制
成员内部类定义在外部类的成员位置(和字段、方法同级),不加 static 修饰。它天然持有对外部类实例的隐式引用(Outer.this),因此能直接访问外部类所有成员——包括私有字段、私有方法、静态成员和非静态成员。
创建对象必须先有外部类实例:new Outer().new Inner()。如果外部类实例为 outer,则写成 outer.new Inner()。
- 不能定义普通静态成员(如
static int x),JDK 16 起允许static final常量,也允许static方法(但极少用) - 可使用任意访问修饰符:
private、public、protected或包级默认 - 当内部类与外部类成员同名时,用 Outer.this.fieldName 明确访问外部类变量
- 常见于需要强耦合的场景,比如 GUI 事件处理器、状态封装类(如
Car.Engine)
静态内部类:独立存在,轻量且安全
静态内部类同样定义在外部类的成员位置,但用 static 修饰。它不持有外部类实例引用,因此无法访问外部类的非静态成员,只能访问 static 字段和方法。
创建对象无需外部类实例:new Outer.StaticInner(),语法更接近普通顶层类。
- 可以自由定义静态成员(字段、方法、代码块),无任何限制
- 内存开销小,没有隐式引用带来的泄漏风险
- 常用于工具类(如
Collections.UnmodifiableList)、Builder 模式(Person.Builder)、API 响应嵌套结构(Response.Data) - 若需访问外部类非静态成员,必须显式传入外部类实例作为参数
局部内部类:限定作用域,只在方法内有效
局部内部类定义在方法、构造器或代码块内部,作用域仅限当前语句块。它既能访问外部类全部成员,也能访问所在方法的局部变量——但这些局部变量必须是 effectively final(实际不可变,编译器可推断其未被修改)。
编译后生成类似 Outer$1LocalClass.class 的独立字节码文件,数字序号按声明顺序递增。
- 不能使用访问修饰符(
public、private等无意义,作用域已由位置决定) - 不能定义
static成员(除static final常量) - 适合封装临时逻辑,比如复杂计算的中间步骤、回调封装、或避免方法体过度膨胀
- 若逻辑极简且只用一次,建议优先用匿名内部类或 Lambda 表达式替代
匿名内部类:无名+一次性,接口/抽象类的快捷实现
匿名内部类是局部内部类的特殊形式,没有类名,定义即实例化,语法为:new 接口名() { ... } 或 new 抽象类名() { ... }。它隐式持有外部类实例引用,也要求所访问的局部变量为 effectively final。
它不能定义构造器,不能有显式名字,也无法复用,本质是“一次性的轻量实现”。
- 适用于快速实现单方法接口(如
Runnable、Comparator)或简单抽象类子类 - 不能继承具体类(只能
extends一个类,且该类不能是 final),但可同时implements多个接口 - Lambda 表达式是它的语法简化版;当逻辑仅含一个方法且无状态捕获时,优先选 Lambda
- 注意:不要序列化匿名内部类,Java 官方明确提示存在兼容性风险











