静态内部类不依赖外部类实例,可独立创建且仅访问外部类静态成员;非静态内部类必须依附外部类实例,持有Outer.this引用,可访问外部类所有成员(含私有实例字段),但存在内存泄漏风险。

静态内部类和非静态内部类的核心区别在于:是否依赖外部类实例。静态内部类不持有外部类对象引用,能独立创建、只访问外部类静态成员;非静态内部类必须依附于外部类实例,可自由访问外部类所有成员(包括私有实例字段和方法)。
怎么用静态内部类
声明时加 static 关键字,创建时不需外部类对象:
- 语法:
public static class StaticInner { ... } - 实例化:
Outer.StaticInner obj = new Outer.StaticInner();(直接通过类名调用,无需先 new Outer) - 可定义自己的静态成员(变量/方法),也能包含非静态成员
- 只能访问外部类的 静态字段和静态方法,访问非静态成员会编译报错
- 常用于工具类、Builder 模式、测试主方法、DTO 或 Entity 的嵌套结构(如
User.Address)
怎么用非静态内部类
默认就是成员内部类,不加 static,创建前必须有外部类实例:
- 语法:
public class Inner { ... } - 实例化:
Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); - 隐式持有一个
Outer.this引用,因此能直接读写外部类的私有实例变量、调用实例方法 - 不能定义静态成员(Java 16 之前明确禁止;Java 16+ 允许 static final 常量,但普通 static 字段/方法仍非法)
- 典型场景:GUI 事件监听器、回调实现、需要封装并操作外部类状态的辅助逻辑
关键区别对比表
内存与生命周期:非静态内部类对象会强引用外部类实例,若被长期持有(如传给线程、静态集合),可能导致外部类无法回收,引发内存泄漏;静态内部类无此风险。
立即学习“Java免费学习笔记(深入)”;
访问权限:非静态内部类可访问外部类全部成员(private 实例字段也行);静态内部类仅限外部类的 static 成员。
编译产物:两者都生成独立的 Outer$Inner.class 文件,但非静态内部类的构造器会自动添加一个 Outer 类型参数,用于传入外部类引用。
序列化:非静态内部类默认不可序列化(因含隐式外部引用),若强行序列化可能抛 NotSerializableException;静态内部类无此限制,更适合作为 DTO 传输。
选哪个?看设计意图
问自己两个问题:
- 这个内部类是否需要读写外部类的 实例状态?需要 → 用非静态;不需要 → 优先用静态
- 它会不会被长期持有(比如缓存、线程池任务、监听器注册)?会 → 静态更安全,避免意外延长外部对象生命周期
多数工具类、配置类、数据结构嵌套类,都适合用静态内部类——语义清晰、开销小、不易出错。


















