系列前面用匿名内部类验证过 this$0 隐藏引用,这篇把范围扩大到一般的非静态内部类,并且真实对照静态嵌套类(static class),用反射把两者在字段和构造器层面的真实差异挖出来。
用反射同时查看 Inner 类的字段列表和构造器参数列表。
StaticNestedVsInnerDemo.java class Inner { void show() { System.out.println(value); } // value 是外部类字段 } Inner inner = outer.new Inner(); // 注意这个创建语法本身就暗示了依赖关系
Inner 类字段个数: 1 Inner 字段: this$0 : StaticNestedVsInnerDemo Inner 构造器参数类型: [class StaticNestedVsInnerDemo]
真实结果验证了两处编译器自动插入的机制:第一,Inner 类真实被编译器加上了一个名为 this$0 的字段,类型就是外部类 StaticNestedVsInnerDemo;第二,Inner 的构造器真实被加上了一个隐藏参数,类型同样是外部类——这就是为什么创建非静态内部类实例必须写成 outer.new Inner() 而不能直接 new Inner():编译器需要真实拿到一个外部类实例传给这个隐藏参数,用来在构造时给 this$0 赋值。
同样用反射查看 StaticNested 类的字段和构造器,对照真实差异。
StaticNested 类字段个数(应为0,没有隐藏引用): 0 StaticNested 构造器参数类型(应为空数组): []
两组真实数据放在一起,给出的工程建议很直接:如果一个嵌套类不需要访问外部类的实例字段或方法(就像这里的 StaticNested 只是逻辑上归属于外部类,不需要 value 这类实例状态),应该优先声明成 static 的——这既避免了不必要的隐藏引用和潜在内存泄漏风险,创建实例时也真实不需要外部实例做前提,更灵活。只有真正需要访问外部实例状态时(比如这里的 Inner.show() 需要读取 value),才有必要使用非静态内部类。
每一行都是真实反射得到的结果。