JVM 記事 - クラス バイトコード ファイルの技術的基礎と実装原則の完全な理解

特別な文字列

定数プールには、完全修飾名単純名、および記述子という3 つの特殊文字を含むシンボリック参照が含まれています。

ここに画像の説明を挿入

すべてのシンボリック参照には、クラスまたはインターフェイスの完全修飾名が含まれます。

  • フィールドへの記号参照には、完全修飾型名に加えて、単純なフィールド名フィールド記述子が含まれます。
  • メソッドへのシンボリック参照には、完全修飾型名に加えて、単純なメソッド名メソッド記述子が含まれます。

シンボリック参照での特殊文字列の使用は、クラス ファイルで定義されたクラスまたはインターフェイスを記述するためにも使用されます。

たとえば、定義されたクラスまたはインターフェイスには完全修飾名が付けられます。クラスまたはインターフェイスで宣言された各フィールドについて、定数プールには単純な名前フィールド記述子が含まれます。定数プールには、クラスまたはインターフェイスで宣言された各メソッドの単純な名前メソッド記述子も含まれています。

完全修飾名

定数プール内のシンボリック参照がクラスまたはインターフェイスを指す場合、そのクラスまたはインターフェイスの完全修飾名が提供されます。クラス ファイルでは、完全修飾名のドットはスラッシュに置き換えられます。

たとえば、クラス ファイルでは、java.lang.Object の完全修飾名は java/lang/Object として表現され、クラス ファイルでは、java.util.Hashtable の完全修飾名は java/util/Hashtable として表現されます。

シンプルな名前

フィールド名とメソッド名は、定数プールに単純な (完全修飾されていない) 名前として表示されます。

たとえば、クラス java.lang.Object のメソッド String toString() を指す定数プール エントリは、「 toString 」という形式のメソッド名を持ちます。クラス java.lang.System のフィールド java.io.PrintStream を指す定数プール エントリは、 「 out 」形式のフィールド名を持ちます。

ディスクリプタ

フィールドおよびメソッドへのシンボリック参照には、完全修飾クラス (またはインターフェイス) 名および単純なフィールド (またはメソッド) 名に加えて、記述子文字列が含まれます。

ここに画像の説明を挿入

フィールドの記述子はフィールドのタイプを示し、メソッドの記述子はメソッドの戻り値、メソッドのパラメータの数、タイプ、順序を示します

フィールドとメソッドの記述子は、次の文脈自由文法によって定義されます。この文法では、非終端記号は FieldType などのイタリック体で表され、終端記号は B や V などの等幅フォントで表されます。

 
 

ジャワ

コードをコピーする

FieldDescriptor: FieldType ComponentType: FieldType FieldType: Base Type ObjectType Array Type BaseType: B C D E I J S z ObjectType: L<classname>; ArrayType: [ ComponentType MethodDescriptor: (ParameterDescriptor) *ReturnDescriptor ParameterDescriptor: FieldType ReturnDescriptor: FieldType V

アスタリスクは、その直前の記号 (間にスペースを入れない) が 0 回以上出現できることを意味します。

基本型ターミネータ

V ターミネータは、メソッドの戻り値が void であることを示します。8 つのプリミティブ型ターミネータ、戻り値記述子ターミネータ V、オブジェクト型ターミネータ L、配列型ターミネータ [、およびメソッド記述子ターミネータ (および ) はそれぞれ ASCII 文字です (外側のヌル文字 null を除く)。これらの文字は、対応する ASCII 文字値を使用して記述することができます。

オブジェクト型の ClassName 部分は完全修飾名であり、その完全修飾名はクラス ファイル内の完全修飾名と同じであり、ドットの代わりにスラッシュが付いています。

ターミネーター タイプ 説明する
B バイト バイト型
C 文字 文字タイプ
D ダブル 倍精度浮動小数点型
F 浮く 単精度浮動小数点型
整数 整数型
J 長さ 長整数型
S 短い 短整数型
Z ブール値 ブール型

注: インスタンス メソッドのメソッド記述子には、すべてのインスタンス メソッドに最初のパラメータとして渡される非表示の this パラメータは含まれません

インスタンス メソッドを呼び出すすべての Java 仮想マシン命令は、暗黙的に this パラメータ (現在のオブジェクトへの参照を表す) を渡します。クラス メソッドはオブジェクトによって呼び出されないため、 this 参照はインスタンス メソッドにのみ渡され、クラス メソッドには渡されないことに注意してください。

メソッド記述子には 255 ワード以内のパラメータのみを含めることができます。たとえば、メソッドの場合、非表示の this パラメーターは 1 ワードを占め、プリミティブ型の long または double は 2 ワードを占め、その他のパラメーターは 1 ワードを占めます。したがって、メソッド記述子が指定された語長内に収まるようにメソッドを設計するときは、パラメータの数とタイプを考慮する必要があります。

フィールド記述子の例

ディスクリプタ フィールド宣言
int I
[[J 長い[][]曲がりくねった道
[Ljava/lang/オブジェクト java.lang.Object[]
Ljava/util/ハッシュテーブル java.util.Hashtable ht
[[[Z ブール値[][][]は準備完了です

メソッド記述子の例

全体的なノード構造モデルは次のとおりです。(参数类型, ......) 返回类型

ディスクリプタ メソッド宣言
()私 int getSize()
()Ljava/lang/String; 文字列 toString()
([Ljava/lang/String;)V void main(String[] args)
()V void wait()
(ジ)V void wait(長いタイムアウト、int nanos)
(ZILjava/lang/String;II)Z booleanregionMatches(booleanignoreCase, int toOffset, String other, int offset, int len)
(IBI)I int read(byte[] b, int off, int len)

定数プール

定数プールは、順序付けされたシーケンスの可変長の cp-info テーブルです。cp-info テーブルの通常の形式を次の図に示します [cp_info テーブルの通常の形式]。

タイプ 名前
1で 鬼ごっこ 1
1で 情報 タグ値によって決定される

cp-info テーブルのタグ (フラグ) 項目は、符号なしバイト型の値で、テーブルの種類と形式を示すために使用されます。cp-infoテーブルは、後述するように全部で11種類あります。

CONSTANT_Utf8_info表

可変長の CONSTANT_Utf8_info テーブルは、UTF-8 形式のバリアントを使用して定数文字列を格納します。このタイプのテーブルには、次のようなさまざまな文字列を保存できます。

  • String オブジェクトなどのリテラル文字列
  • 定義されたクラスとインターフェイスの完全修飾名
  • 定義されているクラスのスーパークラス (存在する場合) の完全修飾名
  • 定義されるクラスおよびインターフェイスの親インターフェイスの完全修飾名。
  • クラスまたはインターフェイス内のフィールドの単純な名前と記述子。
  • クラスまたはインターフェイス内のメソッドの単純な名前と記述子による。
  • 参照されるクラスおよびインターフェイスの完全修飾名
  • 参照されるフィールドの単純な名前と記述子
  • 参照されるメソッドの単純な名前と記述子
  • プロパティに関連付けられた文字列。

CONSTANT_Utf8_infoテーブルの基本型情報

CONSTANT_Utf8_info テーブルには、リテラル文字列、定義されたクラスとインターフェイスの説明、他のクラスまたはインターフェイスへのシンボリック参照、および属性関連の文字列の4 つの基本的な情報タイプが保存されます。

ここに画像の説明を挿入

属性関連の文字列

属性名、クラス ファイルを生成するソース ファイル名、ローカル変数名、記述子などの属性関連の文字列。

UTF-8 エンコード モードでは、characters 内のすべての Unicode 文字を 2 バイトの形式で表現し、ASCII 文字 (null 文字 null を除く) を 1 バイトの形式で表現できます。CONSTANT_Utf8_info の形式は以下のとおりです。

タイプ 名前
ウル 鬼ごっこ 1
u2 長さ 1
ウル バイト 長さ

CONSTANT_Utf8info テーブルの項目は次のとおりです。

鬼ごっこ

Tag 項目の値は CONSTANT_UIf8(1) です。

長さ

Length 項目は、後続の bytes 項目の長さ (バイト数) を示します。

バイト

Bytes 項目には、バリアント UTF-8 形式で保存された文字列内の文字が含まれます。

  • u0001 から u007f までのすべての文字 (ヌル文字を除くすべての ASCII 文字) は 1 バイトで表されます。

  • ヌル文字 null (u0000') および u0080 から u07f までのすべての文字は 2 バイトで表されます

  • u0800' から \ufff' までの文字は 3 バイトで表されます。


CONSTANT_Long_info表

固定長の CONSTANT_Long_info テーブルは、long 型定数を格納するために使用されます。このテーブルには、long 型の値のみが格納され、シンボリック参照は格納されません。CONSTANT_Long_info テーブルの形式を以下に示します。

CONSTANT_Long_info テーブルの形式

タイプ 名前
ウル 鬼ごっこ 1
u8 バイト 1

前に述べたように、long定数プール内のタイプ値 (64 ビット、1 つのエントリは 32​​ ビットを表します) は 2 つのエントリを占有し、次のエントリのインデックス値は現在のエントリのインデックス値より 2 大きい必要があります。この構造体にはCONSTANT_Long_info、次の情報が保存されます。

  • tagCONSTANT_Longフィールドは(5)に設定されます。
  • byteslongフィールドには値がビッグエンディアン形式で保存されます。

したがって、クラス ファイルでは、long値はCONSTANT_Long_info構造体で表され、定数プール内の 2 つのエントリを占有し、次のエントリのインデックス値は現在のエントリのインデックス値より 2 大きくなります。

CONSTANT_Double_info表

「CONSTANT_Double_info」テーブルは、「double」型の定数を格納するために使用される固定長テーブルです。シンボリック参照の格納とは異なり、このテーブルは double 値を格納するためにのみ使用されます。

CONSTANT_Double_info テーブルの形式

タイプ 名前
ウル 鬼ごっこ 1
u8 バイト 1

以下は参考用に最適化されたテキストです。

前述したように、double 型の値は定数プール内の 2 つの位置を占めます。

クラス ファイルでは、double 型のエントリの後に次のエントリが続き、次のエントリのインデックス値は前のエントリのインデックス値より 2 大きくなります。CONSTANT_Double_info テーブルの項目は次のとおりです。

  • タグ項目の値はCONSTANT_Double(6)です。
  • double型の値はバイト項目に上位1番目の形式で格納されます。

CONSTANT_Class_info表

固定长度的CONSTANT_Class_info表使用符号引用来表述类或者接口。无论指向类、接口、字段, 还是方法, 所有的符号引用都包含一个CONSTANT_Class_info表。

CONSTANT_Class_info表的格式

类型 名称 数量
ul tag 1
u2 name_index 1
  • tag: tag项的值为CONSTANT_Class(7)。
  • name_index: name_index项是一个指向CONSTANT_Utf8info表的索引,该表中包含了类或接口的全限定名。在Java中,数组也是对象,因此CONSTANT_Class_info表也可以用来描述数组类。
    • 数组描述符: name_index项指向的CONSTANT_Uf8_info表中包含了数组的描述符,描述符可以作为数组类的名称。例如,一个double[]数组类型的类名为它的描述符[D;一个net.jini.core.lookup.ServiceItem[]数组类型的类名为它的描述符[Lnet/jini/core/lookup/ServiceItem;。

注意,Java数组的维度最多为255,因此数组描述符中的引导符“[”最多为255个。


CONSTANT_String_info

尚定长度的CONSTANT_String_info表用于存储文字字符串值,这些值可以表示为java.lang.String类的实例。该表仅存储文字字符串值,不存储符号引用。

 
 

ini

复制代码

CONSTANT_String_info { u1 tag; u2 string_index; }

下面是CONSTANT_String_info表的格式:

类型 名称 数量
ul tag 1
u2 string_index 1
  • tag: 表示标签,值为CONSTANT_String(8)。
  • string_index: 是一个指向CONSTANT_Utf8_info表的索引,该表中存储了实际的字符串值。通过使用这样的表形式,可以方便地存储和引用字符串值,保证了程序的灵活性和可读性。

CONSTANT_Fieldref_info

固定长度的CONSTANT_Fieldref_info表用于描述指向字段的符号引用。

 
 

ini

复制代码

CONSTANT_Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; }

下面是CONSTANT_Fieldref_info表的格式:

类型 名称 数量
ul tag 1
u2 class_index 1
u2 name_and_type_index 1
  • tag: 表示标签,值为CONSTANT_Fieldref(9)。
  • class_index: 是一个指向CONSTANT_Class_info表的索引,该表中存储了字段所属的类或接口。
  • name_and_type_index: 是一个指向CONSTANT_NameAndType_info表的索引,该表中存储了字段的名称和描述符。

注意事项

class_index所指向的CONSTANT_Class_info不仅代表类,还可能代表接口。虽然接口可以声明字段,并且可以将其声明为公共、静态和final类型,但如前所述,如果其他类使用编译时常量来初始化这些静态final字段,那么class文件不会包含对这些字段的符号引用。然而,class文件可以包含对这些静态final字段常量值的副本。

例如,如果一个类使用在接口中声明的float类型的静态final字段,并且它被初始化为编译时的常量值,那么该类将在自己的常量池中具有一个CONSTANT_Float_info表来存储这个float值的副本。

如果该接口使用在运行时才能计算出的表达式来初始化它的静态final字段,那么在使用该字段的类的常量池中,将会有一个对该接口中字段的符号引用的CONSTANT_Fieldref_info表。


CONSTANT_Method ref_into表

以下是对固定长度的CONSTANT_Methodref_info表使用符号引用来表示类中声明的方法(不包括接口中的方法)进行优化和润色后的描述:固定长度的CONSTANT_Methodref_info表使用符号引用来表示类中声明的方法(不包括接口中的方法)。

下面是CONSTANT_Methodref_info表的格式:

类型 名称 数量
ul tag 1
u2 class_index 1
u2 name_and_type_index 1
  • tag(标签):tag项的值为CONSTANT_Methodref (10)。

  • class_index(类索引):class_index项给出了声明了被引用方法的类的CONSTANT_Class_info表的索引。class_index所指定的CONSTANT_Class_info表必须表示一个类,而不能是接口。指向接口中声明的方法的符号引用应使用CONSTANT_InterfaceMethodref表。

  • name_and_type_index(名称和类型索引):name_and_type_index提供了CONSTANT_NameAndType_info表的索引,该表提供了方法的简单名称和描述符。如果方法的简单名称以"<"(\u003c)符号开头,则该方法必须是一个实例化方法。它的简单名称应为"",并且返回类型必须为void。否则,该方法应该是一个常规方法。


CONSTANT_Interface Method ref_info表

固定长度的CONSTANT_InterfaceMethodref_info表使用符号引用来描述接口中声明的方法,而不包括类中的方法。下面是CONSTANT_InterfaceMethodref_info表的格式:

CONSTANT_InterfaceMethodref_info格式

 
 

ini

复制代码

CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; }

  • tag(标签):tag字段的值为CONSTANT_InterfaceMethodref(11)。
  • class_index(类索引):class_index字段给出了声明了被引用方法的接口的CONSTANT_Class_info表的索引。由class_index指定的CONSTANT_Class_info表必须表示一个接口,而不能表示一个类。对于在类中声明的方法的符号引用,应使用CONSTANT_Methodref表。
  • name_and_type_index (名前とタイプのインデックス) : name_and_type_index フィールドは、メソッドの単純な名前と記述子を提供する CONSTANT_NameAndType_info テーブルへのインデックスを提供します。

この固定長形式により、CONSTANT_InterfaceMethodref_info テーブルはインターフェイスで宣言されたメソッドを正確に記述し、シンボリック参照を通じてこれらのメソッドへの参照を実装できます。


CONSTANT_Name と Type_info 表

固定長の CONSTANT_Namc And Type_info テーブルは、フィールドまたはメソッドへのシンボリック参照の一部を形成します。このテーブルは、参照されるフィールドまたはメソッドの単純な名前と記述子の定数プール エントリを提供します。

CONSTANT_Name_And_Type_info テーブルの形式

 
 

これ

コードをコピーする

CONSTANT_Name_And_Type_info { u1 tag; u2 name_index; u2 description_index; }

CONSTANT_NameAndType_info テーブルの項目は以下のとおりです。

  • tag: タグ項目の値は CONSTANT_NameAndType (12) で、項目が CONSTANT_NameAndType_info の識別子であることを示します。

  • name_index: name_index 項目は、フィールドまたはメソッドの名前を含む CONSTANT_Utf8_info テーブルのインデックスを提供します。名前は、有効な Java プログラミング言語識別子、または「」である必要があります。

  • descriptor_index: descriptor_index 項目は、フィールドまたはメソッドの記述子を含む CONSTANT_Utf8_info テーブルにインデックスを提供します。この記述子は、有効なフィールドまたはメソッド記述子である必要があります。

おすすめ

転載: blog.csdn.net/wdj_yyds/article/details/131739305