Javaクラスファイル

Javaクラスファイルは、Java仮想マシン (JVM) 上で実行可能なJavaバイトコードを含む（.class拡張子付きの）ファイルである。Javaクラスファイルは、Javaクラスを含むJava言語ソースファイル（.javaファイル）からJavaコンパイラによって作成される。ソースファイルに2つ以上のクラスがある場合、各クラスは分割されたクラスファイルとしてコンパイルされる。 JVMは多くのプラットフォームで利用可能であり、あるプラットフォームでコンパイルされたクラスファイルは他のプラットフォームのJVMでも実行できる。これによりJavaはクロスプラットフォームである。 2006年現在[update]、クラスファイルフォーマットの変更はJava Specification Request (JSR) 202の元で検討されている。 Javaクラスファイル構造には10個の基本的な項目がある: マジックナンバー : 0xCAFEBABE クラスファイルフォーマットのバージョン : クラスファイルのマイナーおよびメジャーバージョン 定数プール : クラス定数のプール アクセスフラグ : 例えばクラスがabstractかstaticかなど Thisクラス : 現在のクラス名 スーパークラス : スーパークラスの名前 インタフェース : クラス内の任意のインタフェース フィールド : クラス内の任意のフィールド メソッド : クラス内の任意のメソッド 属性 : クラス内の任意の属性（例えばソースファイル名など） クラスファイルは次の（十六進法の）4バイトのヘッダで識別される : CA FE BA BE（以下のテーブル内の最初の4つ）。このマジックナンバーの歴史についてジェームズ・ゴスリンが説明している。 「私たちはSt Michael's Alleyと呼ばれる場所でよく昼食を取っていた。地元の言い伝えによると、深く暗黒の過去に、有名になる前のグレイトフル・デッドがそこでよく演奏していたという。そこは明確にグレイトフル・デッドにまつわる場所でとてもファンキーな場所だった。ジェリーが死んだ時、人々は少し仏教風な廟を建てることさえした。そこへ行っていた頃、私たちはその場所をCafe Deadと呼んだ。いつしか、それが十六進数であったことに気付いた。私はいくつかのファイルフォーマットを再度繕っていて、マジックナンバーが2つ必要になった。一つは永続的なオブジェクトファイルのため、もう一つはクラスのため。私はオブジェクトファイルフォーマット用にCAFEDEADを使用し、"CAFE" の後にふさわしい4文字の十六進の言葉をgrepして、BABEがヒットしたのでそれを使うことに決めた。その時は、それが歴史の片隅以外の場所に行くような、非常に重要で運命付けられているもののようには見えなかった。そうして、CAFEBABEはクラスファイルフォーマットとなり、CAFEDEADは永続的オブジェクトフォーマットとなった。しかし永続的オブジェクト機能は無くなってしまったため（結局はRMIに置き換えられた）、CAFEDEADも共に無くなった。」 クラスファイルは可変長の項目を含み、組み込まれたファイルのオフセット（またはポインタ）すら含まないため、通常は最初のバイトから最後まで順番に解析される。最も低レベルな点から、ファイルフォーマットはいくつかの基本的なデータ型の点から記述される: u1: 符号なし8ビット整数 u2: ビッグエンディアンバイト順の符号なし16ビット整数 u4: ビッグエンディアンバイト順の符号なし32ビット整数 テーブル: いくつかの型の可変長の配列。テーブルのテーブル内の項目数はカウント数により識別されるが、テーブルのバイト内のサイズは項目それぞれを調査することのみで決定される。 これらの基礎的な型の一部は、前後関係に依存することで次に（文字列や浮動小数点数といった）上位レベルの値として再解釈される。 ワードが一直線に並ぶことは強制されないので、パディングバイトは常に利用されない。 クラスファイルの全てのレイアウトは以下のテーブル内のように見られる。 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）は連続したスロットを取る。しかし二つ目のそのスロットは決して直接使用されない幻のインデックスである。 定数テーブル内の各項目（定数）の型は、最初のバイトであるタグで識別される。このタグに続く数とこれらの解釈は、それ以降タグの値に左右される。正当な定数型とそのタグは以下の通りである: 整数定数型は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バイトコード