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

背景

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

正文

示例代码

请将以下代码保存为 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>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;
}

编译

使用以下命令可以编译 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>Main.java

bash 复制代码
javac Main.java

编译之后,执行 tree . 会看到当前目录下多了一个 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.class \text{Main.class} </math>Main.class 文件 ⬇️

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

1 directory, 2 files

查看 <math xmlns="http://www.w3.org/1998/Math/MathML"> class \text{class} </math>class 文件的内容

使用以下命令可以查看 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.class \text{Main.class} </math>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();
    ...
}
...

观察后,会发现 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>Main.java 中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> 20 20 </math>20 个字段在上面的结果中都出现了。每个字段都有对应的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> flags \text{flags} </math>flags,有的字段还有 <math xmlns="http://www.w3.org/1998/Math/MathML"> Signature \text{Signature} </math>Signature。本文只关心 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor 部分。

理解 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor

<math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor,字面意思是描述符。我觉得可以简单理解成字段的类型信息。在 The Java® Virtual Machine Specification 中的 4.3.2. Field Descriptors 小节 有关于字段的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor 的描述

从中可以看到

<math xmlns="http://www.w3.org/1998/Math/MathML"> FieldDescriptor \text{FieldDescriptor} </math>FieldDescriptor 中的内容是 <math xmlns="http://www.w3.org/1998/Math/MathML"> FieldType \text{FieldType} </math>FieldType。

<math xmlns="http://www.w3.org/1998/Math/MathML"> FieldType \text{FieldType} </math>FieldType 中是以下三种内容之一

  1. <math xmlns="http://www.w3.org/1998/Math/MathML"> BaseType \text{BaseType} </math>BaseType
  2. <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassType \text{ClassType} </math>ClassType
  3. <math xmlns="http://www.w3.org/1998/Math/MathML"> ArrayType \text{ArrayType} </math>ArrayType

1. <math xmlns="http://www.w3.org/1998/Math/MathML"> BaseType \text{BaseType} </math>BaseType 分类

<math xmlns="http://www.w3.org/1998/Math/MathML"> BaseType \text{BaseType} </math>BaseType 中一共有 <math xmlns="http://www.w3.org/1998/Math/MathML"> 8 \text{8} </math>8 种情况,对应 <math xmlns="http://www.w3.org/1998/Math/MathML"> 8 \text{8} </math>8 种基本类型。 4.3.2. Field Descriptors 小节 中提供了如下的表格 (表格的名称是 Table 4.3-A. Interpretation of field descriptors ),表格中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> B, C, D, F, I, J, S, Z \text{B, C, D, F, I, J, S, Z} </math>B, C, D, F, I, J, S, Z 对应 <math xmlns="http://www.w3.org/1998/Math/MathML"> BaseType \text{BaseType} </math>BaseType 分类下的 <math xmlns="http://www.w3.org/1998/Math/MathML"> 8 \text{8} </math>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

我们看一下 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>Main.java 中属于 <math xmlns="http://www.w3.org/1998/Math/MathML"> BaseType \text{BaseType} </math>BaseType 分类的字段在 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.class \text{Main.class} </math>Main.class 文件中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor ⬇️

2. <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassType \text{ClassType} </math>ClassType 分类

<math xmlns="http://www.w3.org/1998/Math/MathML"> ClassType \text{ClassType} </math>ClassType 分类下,对应的内容由以下三部分组成

  • L
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassName \text{ClassName} </math>ClassName (其值是对应类的全限定类名,但需要将 <math xmlns="http://www.w3.org/1998/Math/MathML"> . \text{.} </math>. 替换为 <math xmlns="http://www.w3.org/1998/Math/MathML"> / \text{/} </math>/,细节可以参考 4.2.1. Binary Class and Interface Names 小节
  • ;

我们来看几个例子 ⬇️

全限定类名 ➡️ <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassName \text{ClassName} </math>ClassName ➡️ L <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassName \text{ClassName} </math>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;

我们看一下 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>Main.java 中属于 <math xmlns="http://www.w3.org/1998/Math/MathML"> ClassType \text{ClassType} </math>ClassType 分类的字段在 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.class \text{Main.class} </math>Main.class 文件中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor ⬇️

3. <math xmlns="http://www.w3.org/1998/Math/MathML"> ArrayType \text{ArrayType} </math>ArrayType 分类

<math xmlns="http://www.w3.org/1998/Math/MathML"> ArrayType \text{ArrayType} </math>ArrayType 分类下,对应的内容由以下三部分组成

  • [
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ComponentType \text{ComponentType} </math>ComponentType (它的内容是 $\text{FieldType},所以这里出现了递归的情况)

我们来看几个例子 ⬇️

<math xmlns="http://www.w3.org/1998/Math/MathML"> java \text{java} </math>java 代码中的类型 ➡️ <math xmlns="http://www.w3.org/1998/Math/MathML"> ComponentType \text{ComponentType} </math>ComponentType ➡️ [ <math xmlns="http://www.w3.org/1998/Math/MathML"> ComponentType \text{ComponentType} </math>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;

我们看一下 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.java \text{Main.java} </math>Main.java 中属于 <math xmlns="http://www.w3.org/1998/Math/MathML"> ArrayType \text{ArrayType} </math>ArrayType 分类的字段在 <math xmlns="http://www.w3.org/1998/Math/MathML"> Main.class \text{Main.class} </math>Main.class 文件中的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor ⬇️

至此,相信您已经了解了 <math xmlns="http://www.w3.org/1998/Math/MathML"> class \text{class} </math>class 文件中字段的 <math xmlns="http://www.w3.org/1998/Math/MathML"> descriptor \text{descriptor} </math>descriptor 的格式。

参考资料

The Java® Virtual Machine Specification 中的

相关推荐
我是一颗柠檬5 小时前
【MySQL全面教学】MySQL基础与环境搭建Day1(2026年)
数据库·后端·sql·mysql·database
我是一颗柠檬5 小时前
【MySQL全面教学】MySQL数据类型详解Day2(2026年)
数据库·后端·sql·mysql·database
500845 小时前
Graph Engine 是什么,为什么需要它
java·人工智能·性能优化·ocr·wpf
怒放吧德德5 小时前
JDK 版本一键切换工具(windows)
后端·shell
未若君雅裁5 小时前
服务雪崩、降级、熔断与服务保护
java·微服务
就叫_这个吧5 小时前
Java实现线程间的通讯--使用synchronized关键字和JUC方式实现
java·开发语言
爱上语文5 小时前
2026在线会议软件推荐:8款工具对比评测与多人协作选型指南
后端
学习中.........5 小时前
JVM 垃圾回收核心技术、演进全景与生产调优规范
java·jvm·测试工具
小小编程路5 小时前
C++类作用域
java·jvm·c++