Java内部类编译后生成Outer$Inner.class等带$符号的独立class文件,这是JVM规范要求的二进制名规则;$连接内外层类名,类加载器据此路径查找,且反编译可见this$0、access$xxx等合成结构。

Java 编译器在生成字节码时,会将内部类(包括成员内部类、匿名内部类、局部内部类)编译为独立的 `.class` 文件,并用 `$` 符号连接外层类名与内部类名。这不是语法糖的随意标记,而是编译期严格约定的命名规则,直接反映类的嵌套关系和访问权限机制。
内部类文件名中的 $ 是编译器生成的分隔符
比如:
-
Outer.class对应外部类 -
Outer$Inner.class对应成员内部类Inner -
Outer$1.class对应匿名内部类(按出现顺序编号) -
Outer$2.class对应第二个匿名类或局部类
这个 `$` 不是 Java 源码中允许的标识符字符,所以你无法在源码里写 Outer$Inner;它纯属编译器输出产物,用于 JVM 正确识别和加载嵌套类型。
反编译后能看到合成字段和桥接方法
反编译 Outer$Inner.class 通常会看到:
立即学习“Java免费学习笔记(深入)”;
- 一个隐式构造器参数:指向外层类实例的引用(如
final Outer this$0) - 编译器自动生成的包级访问字段(
access$xxx),用于突破 private 访问限制 - 可能存在的桥接方法(bridge method),解决泛型擦除或继承签名不匹配问题
这些结构不是开发者写的,而是编译器为保障语义正确性插入的“胶水代码”,反编译工具(如 JD-GUI、CFR、Jad)能还原出接近源码的表达,但需注意它们本质是字节码层面的实现细节。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
通过 javap 查看原始字节码结构
比图形化反编译更底层的方式是用 JDK 自带的 javap:
-
javap -c Outer$Inner查看字节码指令,确认this$0如何在构造器中被存储 -
javap -p Outer$Inner显示所有字段(含 synthetic 字段),识别编译器注入的访问桥接字段 -
javap -s Outer$Inner查看每个方法的签名,发现桥接方法的 descriptor 与源码声明不一致
例如,当内部类访问外部类的 private 成员时,javap 会显示一个 static synthetic 方法,这就是编译器生成的“访问器”,JVM 允许它绕过访问控制检查。
匿名类和局部类的 $ 编号有确定性规律
编号不是随机的,而是按源码中定义顺序从 1 开始递增:
- 同一个方法内多个 lambda 或匿名 new,按书写顺序得
$1、$2… - 不同方法里的匿名类彼此独立编号,不会冲突
- 局部类(带名字的 class 声明在方法内)也会被命名为
Outer$LocalName,而非数字
这种命名策略让 JVM 能唯一标识每个嵌套类型,也使得调试器、序列化、反射等机制可以准确定位到对应类。
理解 $ 符号背后的实际字节码行为,关键在于把反编译结果和 javap 输出对照着看——前者帮你重建逻辑,后者告诉你 JVM 真正执行什么。

















