[Java] 如何理解 class 文件中字段的 descriptor?

背景

在日常开发过程中,我们有时候需要查看 class \text{class} class 文件的内容。如果我们对 class \text{class} class 文件的结构有基本的了解,那么就会事半功倍。由于这个话题很大,而且我自己的水平也有限,所以每次只写一个很小的主题。本文的主题是理解 class \text{class} class 文件中字段的 descriptor \text{descriptor} descriptor。

正文

示例代码

请将以下代码保存为 Main.java \text{Main.java} Main.java

java 复制代码
import java.util.List;
import java.util.Map;

public class Main {
  // base type examples
  byte f1;
  char f2;
  double f3;
  float f4;
  int f5;
  long f6;
  short f7;
  boolean f8;

  // array examples
  int[] f9;
  double[][] f10;
  long[][][][] f11;
  
  // class type examples
  Boolean f12;
  Long f13;
  Object f14;
  List<Integer> f15;
  Map<String, List<Long>> f16;
  List<?> f17;
  Void f18;
  
  // more array examples
  Boolean[] f19;
  Integer[][][] f20;
}

编译

使用以下命令可以编译 Main.java \text{Main.java} Main.java

bash 复制代码
javac Main.java

编译之后,执行 tree . 会看到当前目录下多了一个 Main.class \text{Main.class} Main.class 文件 ⬇️

text 复制代码
.
├── Main.class
└── Main.java

1 directory, 2 files

查看 class \text{class} class 文件的内容

使用以下命令可以查看 Main.class \text{Main.class} Main.class 文件的详细内容

bash 复制代码
javap -v -p Main

完整的结果有点长,我把本文关心的部分复制到的下方 ⬇️ (与本文无关的内容用 ... 表示)

text 复制代码
...
public class Main
   ...
{
  byte f1;
    descriptor: B
    flags: (0x0000)

  char f2;
    descriptor: C
    flags: (0x0000)

  double f3;
    descriptor: D
    flags: (0x0000)

  float f4;
    descriptor: F
    flags: (0x0000)

  int f5;
    descriptor: I
    flags: (0x0000)

  long f6;
    descriptor: J
    flags: (0x0000)

  short f7;
    descriptor: S
    flags: (0x0000)

  boolean f8;
    descriptor: Z
    flags: (0x0000)

  int[] f9;
    descriptor: [I
    flags: (0x0000)

  double[][] f10;
    descriptor: [[D
    flags: (0x0000)

  long[][][][] f11;
    descriptor: [[[[J
    flags: (0x0000)

  java.lang.Boolean f12;
    descriptor: Ljava/lang/Boolean;
    flags: (0x0000)

  java.lang.Long f13;
    descriptor: Ljava/lang/Long;
    flags: (0x0000)

  java.lang.Object f14;
    descriptor: Ljava/lang/Object;
    flags: (0x0000)

  java.util.List<java.lang.Integer> f15;
    descriptor: Ljava/util/List;
    flags: (0x0000)
    Signature: #40                          // Ljava/util/List<Ljava/lang/Integer;>;

  java.util.Map<java.lang.String, java.util.List<java.lang.Long>> f16;
    descriptor: Ljava/util/Map;
    flags: (0x0000)
    Signature: #43                          // Ljava/util/Map<Ljava/lang/String;Ljava/util/List<Ljava/lang/Long;>;>;

  java.util.List<?> f17;
    descriptor: Ljava/util/List;
    flags: (0x0000)
    Signature: #45                          // Ljava/util/List<*>;

  java.lang.Void f18;
    descriptor: Ljava/lang/Void;
    flags: (0x0000)

  java.lang.Boolean[] f19;
    descriptor: [Ljava/lang/Boolean;
    flags: (0x0000)

  java.lang.Integer[][][] f20;
    descriptor: [[[Ljava/lang/Integer;
    flags: (0x0000)

  public Main();
    ...
}
...

观察后,会发现 Main.java \text{Main.java} Main.java 中的 20 20 20 个字段在上面的结果中都出现了。每个字段都有对应的 descriptor \text{descriptor} descriptor 和 flags \text{flags} flags,有的字段还有 Signature \text{Signature} Signature。本文只关心 descriptor \text{descriptor} descriptor 部分。

理解 descriptor \text{descriptor} descriptor

descriptor \text{descriptor} descriptor,字面意思是描述符。我觉得可以简单理解成字段的类型信息。在 The Java® Virtual Machine Specification 中的 4.3.2. Field Descriptors 小节 有关于字段的 descriptor \text{descriptor} descriptor 的描述

从中可以看到

FieldDescriptor \text{FieldDescriptor} FieldDescriptor 中的内容是 FieldType \text{FieldType} FieldType。

FieldType \text{FieldType} FieldType 中是以下三种内容之一

  1. BaseType \text{BaseType} BaseType
  2. ClassType \text{ClassType} ClassType
  3. ArrayType \text{ArrayType} ArrayType

1. BaseType \text{BaseType} BaseType 分类

BaseType \text{BaseType} BaseType 中一共有 8 \text{8} 8 种情况,对应 8 \text{8} 8 种基本类型。 4.3.2. Field Descriptors 小节 中提供了如下的表格 (表格的名称是 Table 4.3-A. Interpretation of field descriptors ),表格中的 B, C, D, F, I, J, S, Z \text{B, C, D, F, I, J, S, Z} B, C, D, F, I, J, S, Z 对应 BaseType \text{BaseType} BaseType 分类下的 8 \text{8} 8 种情况

FieldType term Type
B byte
C char
D double
F float
I int
J long
L ClassName ; Named class or interface type
S short
Z boolean
[ ComponentType Array of given component type

我们看一下 Main.java \text{Main.java} Main.java 中属于 BaseType \text{BaseType} BaseType 分类的字段在 Main.class \text{Main.class} Main.class 文件中的 descriptor \text{descriptor} descriptor ⬇️

2. ClassType \text{ClassType} ClassType 分类

ClassType \text{ClassType} ClassType 分类下,对应的内容由以下三部分组成

我们来看几个例子 ⬇️

全限定类名 ➡️ ClassName \text{ClassName} ClassName ➡️ L ClassName \text{ClassName} ClassName ;
java.lang.Object java/lang/Object Ljava/lang/Object;
java.lang.Boolean java/lang/Boolean Ljava/lang/Boolean;
java.util.List java/util/List Ljava/util/List;

我们看一下 Main.java \text{Main.java} Main.java 中属于 ClassType \text{ClassType} ClassType 分类的字段在 Main.class \text{Main.class} Main.class 文件中的 descriptor \text{descriptor} descriptor ⬇️

3. ArrayType \text{ArrayType} ArrayType 分类

ArrayType \text{ArrayType} ArrayType 分类下,对应的内容由以下三部分组成

  • [
  • ComponentType \text{ComponentType} ComponentType (它的内容是 $\text{FieldType},所以这里出现了递归的情况)

我们来看几个例子 ⬇️

java \text{java} java 代码中的类型 ➡️ ComponentType \text{ComponentType} ComponentType ➡️ [ ComponentType \text{ComponentType} ComponentType
int[] I [I
java.lang.Boolean[] Ljava/lang/Boolean; [Ljava/lang/Boolean;
java.lang.Boolean[][] [Ljava/lang/Boolean; [[Ljava/lang/Boolean;
java.lang.Boolean[][][] [[Ljava/lang/Boolean; [[[Ljava/lang/Boolean;

我们看一下 Main.java \text{Main.java} Main.java 中属于 ArrayType \text{ArrayType} ArrayType 分类的字段在 Main.class \text{Main.class} Main.class 文件中的 descriptor \text{descriptor} descriptor ⬇️

至此,相信您已经了解了 class \text{class} class 文件中字段的 descriptor \text{descriptor} descriptor 的格式。

参考资料

The Java® Virtual Machine Specification 中的

相关推荐
北城以北88881 小时前
RocketMQ简介
java·spring boot·后端·rocketmq
折哥的程序人生 · 物流技术专研8 小时前
Java面试85题图解版 · 特别篇:2026后端高频面试题复盘(算法底层逻辑+高并发架构设计全解析,附Java实战代码)
java·网络·数据库·算法·面试
GoGeekBaird8 小时前
从 Prompt Engineering 到 Loop Engineering,我觉得 AI 开发这事儿终于开始变味了
后端·github
一条泥憨鱼8 小时前
【Redis】数据类型和常用命令
java·数据库·redis·后端·缓存
云烟成雨TD9 小时前
Spring AI Alibaba 1.x 系列【78】沙箱(Sandbox)
java·人工智能·spring
程序员二叉9 小时前
【Java】 异常高频面试题精讲 | 易错点+对比总结
java·开发语言·面试
周航宇JoeZhou9 小时前
JB3-9-SpringAI(二)
java·ai·agent·多智能体·调度·智能体·观察
好家伙VCC9 小时前
Web Components主题热切换方案揭秘
java·前端
慕木沐9 小时前
Google ADK Java 1.0版本 核心机制与实战 Demo
java·开发语言·python
Oneslide9 小时前
初始化微信小程序
后端