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

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

歴史

2006年現在、クラスファイルフォーマットの変更は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ライクなプログラミング言語による表現

Cは複雑な、構造体内の可変長配列をサポートしていないため、以下のコードはコンパイル不可能で、デモンストレーションとしてのみ役立つ。

定数プール

定数プールは、大部分のリテラル定数値がストアされる場所である。ここには全ての種類の数、文字列、識別子名、クラスおよびメソッドへの参照、そしてタイプデスクリプタといった値が含まれる。定数テーブル内の明確な定数への全てのインデックスや参照は、インデックスがテーブル内の最初の定数を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バイトコード

脚注

参考文献

  • Tim Lindholm, Frank Yellin (1999). The Java Virtual Machine Specification (Second Edition ed.). Prentice Hall. ISBN 0-201-43294-3. http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html 2008年10月13日閲覧。  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.

Javaとは何?特徴やできること、開発手順をわかりやすく解説! コードカキタイ

Java の 1つのファイルに複数のクラス Delft スタック

Javaクラスファイルの読み方

Javaのファイル名とクラス名の関係 ~Java初心者の備忘録~ pensukeblog

详解Java的类文件结构(.class文件的结构) 二哥的Java进阶之路