Javaクラスファイル

Javaクラスファイルは、Java仮想マシン (JVM) 上で実行可能なJavaバイトコードを含む（拡張子付きの）ファイルである。Javaクラスファイルは、Javaクラスを含むJava言語ソースファイル（ファイル）からJavaコンパイラによって作成される。ソースファイルに2つ以上のクラスがある場合、各クラスは分割されたクラスファイルとしてコンパイルされる。

JVMは多くのプラットフォームで利用可能であり、あるプラットフォームでコンパイルされたクラスファイルは他のプラットフォームのJVMでも実行できる。これによりJavaはクロスプラットフォームである。

歴史
、クラスファイルフォーマットの変更はJava Specification Request (JSR) 202の元で検討されている。JSR 202 Java Class File Specification Update

ファイルレイアウトと構造
項目
Javaクラスファイル構造には10個の基本的な項目がある:
 マジックナンバー : 0xCAFEBABE
 クラスファイルフォーマットのバージョン : クラスファイルのマイナーおよびメジャーバージョン
 定数プール : クラス定数のプール
 アクセスフラグ : 例えばクラスがabstractかstaticかなど
 Thisクラス : 現在のクラス名
 スーパークラス : スーパークラスの名前
 インタフェース : クラス内の任意のインタフェース
 フィールド : クラス内の任意のフィールド
 メソッド : クラス内の任意のメソッド
 属性 : クラス内の任意の属性（例えばソースファイル名など）

マジックナンバー
クラスファイルは次の（十六進法の）4バイトのヘッダで識別される : CA FE BA BE（以下のテーブル内の最初の4つ）。このマジックナンバーの歴史についてジェームズ・ゴスリンが説明している。James Gosling private communication to Bill Bumgarner

「私たちはSt Michael's Alleyと呼ばれる場所でよく昼食を取っていた。地元の言い伝えによると、深く暗黒の過去に、有名になる前のグレイトフル・デッドがそこでよく演奏していたという。そこは明確にグレイトフル・デッドにまつわる場所でとてもファンキーな場所だった。ジェリーが死んだ時、人々は少し仏教風な廟を建てることさえした。そこへ行っていた頃、私たちはその場所をCafe Deadと呼んだ。いつしか、それが十六進数であったことに気付いた。私はいくつかのファイルフォーマットを再度繕っていて、マジックナンバーが2つ必要になった。一つは永続的なオブジェクトファイルのため、もう一つはクラスのため。私はオブジェクトファイルフォーマット用にCAFEDEADを使用し、"CAFE" の後にふさわしい4文字の十六進の言葉をgrepして、BABEがヒットしたのでそれを使うことに決めた。その時は、それが歴史の片隅以外の場所に行くような、非常に重要で運命付けられているもののようには見えなかった。そうして、CAFEBABEはクラスファイルフォーマットとなり、CAFEDEADは永続的オブジェクトフォーマットとなった。しかし永続的オブジェクト機能は無くなってしまったため（結局はRMIに置き換えられた）、CAFEDEADも共に無くなった。」

一般的レイアウト
クラスファイルは可変長の項目を含み、組み込まれたファイルのオフセット（またはポインタ）すら含まないため、通常は最初のバイトから最後まで順番に解析される。最も低レベルな点から、ファイルフォーマットはいくつかの基本的なデータ型の点から記述される:

 u1: 符号なし8ビット整数
 u2: ビッグエンディアンバイト順の符号なし16ビット整数
 u4: ビッグエンディアンバイト順の符号なし32ビット整数
 テーブル: いくつかの型の可変長の配列。テーブルのテーブル内の項目数はカウント数により識別されるが、テーブルのバイト内のサイズは項目それぞれを調査することのみで決定される。

これらの基礎的な型の一部は、前後関係に依存することで次に（文字列や浮動小数点数といった）上位レベルの値として再解釈される。
ワードが一直線に並ぶことは強制されないので、パディングバイトは常に利用されない。
クラスファイルの全てのレイアウトは以下のテーブル内のように見られる。

 バイトオフセット サイズ 型あるいは値 記述 0 4バイト u1 =0xCA 十六進 クラスファイルフォーマットに適合するファイルを識別するために使用されるマジックナンバー (CAFEBABE) 1 u1 =0xFE 十六進 2 u1 =0xBA 十六進 3 u1 =0xBE 十六進 4 2バイト u2 使用されるクラスファイルフォーマットのマイナーバージョン数 5 6 2バイト u2 使用されるクラスファイルフォーマットのメジャーバージョン数。JDK 1.1 = 45（0x2D 十六進）、JDK 1.2 = 46（0x2E 十六進）、JDK 1.3 = 47（0x2F 十六進）、JDK 1.4 = 48（0x30 十六進）、J2SE 5.0 = 49（0x31 十六進）、JavaSE 6.0 = 50（0x32 十六進）、JavaSE 7 = 51（0x33 十六進）、以降メジャーバージョン毎に1ずつ加算。初期バージョン数の詳細についてはThe JavaTM Virtual Machine Specification 2nd editionの脚注を参照すること。 7 8 2バイト u2 定数プールカウント、以下の定数プールテーブル内のエントリ数。このカウントは少なくとも1つは実在のエントリ数よりも大きい。以下の議論を参照すること。 9 10 cpsize（変数） テーブル 定数プールテーブル、リテラル数、文字列、そしてクラスやメソッドへの参照といった項目を含む、可変長の定数プールエントリ。合計エントリ（定数テーブルカウント - 1）数を含む、1から始まり索引付けされる（脚注を参照すること）。 ... ... ... 10+cpsize 2バイト u2 ビットマスクによるアクセスフラグ 11+cpsize 12+cpsize 2バイト u2 「クラス」型エントリの定数プールへのインデックスである、thisクラスを識別する 13+cpsize 14+cpsize 2バイト u2 「クラス」型エントリの定数プールへのインデックスである、スーパークラスを識別する 15+cpsize 16+cpsize 2バイト u2 インタフェースカウント、以下のインタフェーステーブル内のエントリの数 17+cpsize 18+cpsize isize（変数） テーブル インタフェーステーブル、可変長インタフェースの配列 ... ... ... 18+cpsize+isize 2バイト u2 変数カウント、以下のフィールド内のエントリの数 19+cpsize+isize 20+cpsize+isize fsize（変数） テーブル フィールドテーブル、フィールドの可変長配列 ... ... ... 20+cpsize+isize+fsize 2バイト u2 メソッドカウント、以下のメソッドテーブル内のエントリ数 21+cpsize+isize+fsize 22+cpsize+isize+fsize msize（変数） テーブル メソッドテーブル、メソッドの可変長配列 ... ... ... 22+cpsize+isize+fsize+msize 2バイト u2 属性カウント、以下の属性テーブル内のエントリ数 23+cpsize+isize+fsize+msize 24+cpsize+isize+fsize+msize asize（変数） テーブル 属性テーブル、属性の可変長配列 ... ... ...

Cライクなプログラミング言語による表現
Cは複雑な、構造体内の可変長配列をサポートしていないため、以下のコードはコンパイル不可能で、デモンストレーションとしてのみ役立つ。

struct Class_File_Format {
   u4 magic_number;   

   u2 minor_version;   
   u2 major_version;   

   u2 constant_pool_count;   

   cp_info constant_pool[constant_pool_count - 1];

   u2 access_flags;

   u2 this_class;
   u2 super_class;

   u2 interfaces_count;   

   u2 interfaces[interfaces_count];

   u2 fields_count;   
   field_info fields[fields_count];

   u2 methods_count;
   method_info methods[methods_count];

   u2 attributes_count;   
   attribute_info attributes[attributes_count];
}

定数プール
定数プールは、大部分のリテラル定数値がストアされる場所である。ここには全ての種類の数、文字列、識別子名、クラスおよびメソッドへの参照、そしてタイプデスクリプタといった値が含まれる。定数テーブル内の明確な定数への全てのインデックスや参照は、インデックスがテーブル内の最初の定数を1に指し示す（インデックス値0は不正）、16ビット（u2型）数で与えられる。

ファイルフォーマット開発中の歴史的な選択のため、定数テーブル内の定数の数は、テーブルの先にある定数テーブルカウントと実際には同じではない。最初に、テーブルは（0ではなく）1で始まるようインデックス付けされ、そのためにカウントは実際には最大インデックスとして解釈されるべきである。加えて、定数の2つの型（longおよびdouble）は連続したスロットを取る。しかし二つ目のそのスロットは決して直接使用されない幻のインデックスである。

定数テーブル内の各項目（定数）の型は、最初のバイトであるタグで識別される。このタグに続く数とこれらの解釈は、それ以降タグの値に左右される。正当な定数型とそのタグは以下の通りである:

 タグバイト 追加のバイト 定数の解説 1 2+xバイト（変数） UTF-8 (Unicode) 文字列 : 直接続くエンコードされた文字列内の数を示す、16ビット数の接頭辞が付くキャラクタ文字列。エンコーディングは実際にはUTF-8ではなく、Unicode標準のエンコーディング形式のわずかな修正を含むことに注意すること。 3 4バイト Integer : ビッグエンディアンフォーマットによる符号付き32ビット2の補数 4 4バイト Float : 32ビット単精度IEEE 754浮動小数点数 5 8バイト Long : ビッグエンディアンフォーマットによる符号付き64ビット2の補数（定数テーブルの2つのスロットを占める） 6 8バイト Double : 64ビット倍精度IEEE 754浮動小数点数（定数テーブルの2つのスロットを占める） 7 2バイト クラス参照 : （内部フォーマットによる）完全修飾型クラス名を含むUTF-8文字列による定数テーブル内のインデックス（ビッグエンディアン） 8 2バイト 文字列参照 : UTF-8による定数プール内のインデックス（ビッグエンディアン） 9 4バイト フィールド参照 : 定数プール内にある2つのインデックス、最初はクラス参照で次は名前および型の記述（ビッグエンディアン） 10 4バイト メソッド参照 : 定数プール内にある2つのインデックス、最初はクラス参照で次は名前および型の記述（ビッグエンディアン） 11 4バイト インタフェース参照 : 定数プール内にある2つのインデックス、最初はクラス参照で次は名前および型の記述（ビッグエンディアン） 12 4バイト 名前および型の記述 : UTF-8による定数プール内のインデックス、最初は名前（識別子）を表し次は特別にエンコードされた型

整数定数型はintegerとlongの2つしかない。boolean、byte、そしてshortといった上位レベル言語で見られる他の定数型は、integer定数として表されなければならない。

完全修飾されたJavaのクラス名は、「java.lang.Object」のように慣例的にドットで区分けされる。しかしながら低レベルなクラス参照定数内においては、内部形式は「java/lang/Object」のように、代わりにスラッシュを使用する。

Unicode文字列は、「UTF-8文字列」とあだ名されているにも係らず、実際にはUnicode標準に従ってエンコードされておらずそれと似たような形式である。それら2つには違いがある（完全な議論についてはUTF-8を参照すること）。最初に、コードポイントU+0000は、標準的な1バイト00にエンコードする代わりに、2バイトのシーケンスC0 80としてエンコードされる。
2つ目の違いは、（U+10000および上記としてBasic Multilingual Planeの外側にある）補足する文字が、UTF-8を用いて直接エンコードするのではなくUTF-16に似たサロゲートペア構造を用いてエンコードすることである。この場合、2つのサロゲートの各々がUTF-8において分割してエンコードされる。例えばU+1D11Eは、4バイトのUTF-8エンコーディングF0 9D 84 9Eではなく、6バイトのシーケンスED A0 B4 ED B4 9Eとしてエンコードされる。

関連項目
Javaバイトコード

脚注

参考文献
 The official defining document of the Java Virtual Machine, which includes the class file format. Both the first and second editions of the book are freely available online for viewing and/or download.

Category:Javaプラットフォーム
Category:ファイルフォーマット