静态内部类不持有外部类引用,可独立创建且无内存泄漏风险;成员内部类隐式持有外部类强引用,必须依附外部实例,易导致内存泄漏。

静态内部类和成员内部类,创建方式就暴露了本质区别
根本不在语法糖上,而在对象生命周期的绑定关系上。一个能独立存在,一个必须依附外部实例。
-
Outer.Inner实例化前必须先有new Outer(),否则编译报错:error: an enclosing instance that contains Outer.Inner is required -
Outer.StaticInner可直接 new,不依赖任何外部对象:new Outer.StaticInner() - 成员内部类字节码里会自动生成一个隐式构造参数
Outer this$0,而静态内部类没有
访问外部类成员时,编译器帮你做了什么
不是“语法允许”,而是“引用存在”才让访问成为可能。成员内部类能读写 private int x,靠的是它偷偷持有了外部类对象的强引用;静态内部类连这个引用都没有,自然无权碰实例字段。
- 成员内部类中写
x++等价于this$0.x++—— 编译器自动补全了外部实例引用 - 静态内部类若强行访问非静态字段,编译直接失败:
non-static variable xxx cannot be referenced from a static context - 想在静态内部类里用实例成员?必须显式传入或创建:
Outer o = new Outer(); o.instanceField;
内存泄漏风险:非静态内部类是“隐式长引用”的高发区
只要成员内部类实例被长期持有(比如注册成监听器、放进静态集合、传给线程池),它背后的 this<p>只要成员内部类实例被长期持有(比如注册成监听器、放进静态集合、传给线程池),它背后的 <code>this$0 就会把整个外部类对象钉在堆里,哪怕外部类本该被回收。
- 典型场景:Activity 里定义匿名内部类做网络回调,回调未完成 Activity 已 finish → Activity 泄漏
- 静态内部类没这问题:它不持有
this$0,GC 可正常回收外部类实例 - 修复方案不是“删掉内部类”,而是:该静态的地方加
static;必须用实例时,改用弱引用包装(WeakReference<outer></outer>)
选哪个?看它要不要“知道外面是谁”
别纠结“嵌套好看”,只问一句:这个类的逻辑,是否天然属于某个外部对象的生命周期?
立即学习“Java免费学习笔记(深入)”;
- 要访问
this.field或调用this.method()→ 用成员内部类(如ArrayList.iterator()返回的Itr) - 只封装工具逻辑、配置、DTO、Builder —— 和外部实例状态无关 → 无条件选
static(如HashMap.Node、OkHttp.Builder内部类) - 不确定?先写
static;编译报错说“无法访问非静态成员”,再删掉static—— 这个顺序比反过来安全得多










