Javaクラスファイルとは、 Java仮想マシン(JVM)上で実行可能なJavaバイトコードを含むファイル(ファイル名拡張子は.class )です。Javaクラスファイルは通常、Javaクラスを含むJavaプログラミング言語ソースファイル(.javaファイル)からJavaコンパイラによって生成されます(ただし、他のJVM言語を使用してクラスファイルを作成することもできます)。ソースファイルに複数のクラスが含まれている場合、各クラスは個別のクラスファイルにコンパイルされます。そのため、単一のクラスのバイトコードが含まれていることから、 .classファイルと呼ばれます。
JVMは多くのプラットフォームで利用可能であり、あるプラットフォームでコンパイルされたクラスファイルは、別のプラットフォームのJVMでも実行できます。これにより、Javaアプリケーションはプラットフォームに依存しないものとなります。
2006年12月11日、 Java仕様要求(JSR)202に基づき、クラスファイル形式が変更されました。[ 1 ]
Javaクラスファイルの構造には、基本的に10のセクションがあります。
クラスファイルは、次の 4バイトのヘッダー( 16 進数)で識別されますCA FE BA BE(下の表の最初の 4 つのエントリ)。この魔法の数字の由来は、ジェームズ・ゴスリングがパロアルトのレストランに言及して説明しました。[ 2 ]
「私たちはよくセント・マイケルズ・アレーという店でランチを食べていました。地元の言い伝えによると、はるか昔、グレイトフル・デッドがブレイクする前にそこで演奏していたそうです。かなりファンキーな場所で、まさにグレイトフル・デッドっぽい雰囲気でした。ジェリーが亡くなった時には、小さな仏教風の祠まで建てられました。私たちがよくそこに行っていた時は、その店をカフェ・デッドと呼んでいました。いつしか、これが16進数であることが分かったんです。私はファイルフォーマットのコードを改訂していて、マジックナンバーが2つ必要でした。1つは永続オブジェクトファイル用、もう1つはクラス用です。オブジェクトファイルフォーマットにはCAFEDEADを使い、その後に続く4文字の16進数ワードをgrepで検索していたところ(良いテーマだと思ったので)、BABEが出てきたので、それを使うことにしました。当時は、それほど重要なことでも、歴史のゴミ箱行きになる運命にあるようにも思えませんでした。こうしてCAFEBABEがクラスファイルフォーマットになり、CAFEDEADが永続ファイルフォーマットになったのです。」オブジェクト形式。しかし、永続オブジェクト機能は廃止され、それに伴いCAFEDEADの使用も廃止されました。最終的にはRMIに置き換えられました。
クラスファイルには可変サイズの項目が含まれており、埋め込みファイルオフセット(またはポインタ)も含まれていないため、通常は最初のバイトから末尾に向かって順次解析されます。最も低レベルでは、ファイル形式はいくつかの基本的なデータ型で記述されます。
これらの基本型の一部は、文脈に応じて、文字列や浮動小数点数などの上位レベルの値として再解釈されます。ワードアライメントは強制されないため、パディングバイトは一切使用されません。クラスファイルの全体的なレイアウトは、次の表に示すとおりです。
以下は、.classファイルを C スタイルの構造体として表現したものです。
struct ClassFileFormat { u4 magicNumber ;u2マイナーバージョン; u2メジャーバージョン;u2 constantPoolCount ; ConstantPoolInfo [ constantPoolCount - 1 ] constantPool ;u2アクセスフラグ;u2 thisClass ; u2 superClass ;u2インターフェース数; u2 [インターフェース数]インターフェース;u2 fieldsCount ; FieldInfo [ fieldsCount ] fields ;u2 methodsCount ; MethodInfo [ methodsCount ]メソッド;u2 attributesCount ; AttributeInfo [ attributesCount ] attributes ; }定数プールテーブルには、ほとんどのリテラル定数値が格納されます。これには、あらゆる種類の数値、文字列、識別子名、クラスやメソッドへの参照、型記述子などの値が含まれます。定数プールテーブル内の特定の定数へのすべてのインデックス(参照)は、16ビット(型u2)の数値で指定され、インデックス値1はテーブル内の最初の定数を参照します(インデックス値0は無効です)。
ファイル形式の開発中に下された歴史的な選択により、定数プール テーブル内の定数の数は、テーブルの前の定数プール カウントとは実際には同じではありません。まず、テーブルのインデックスは (0 ではなく) 1 から始まりますが、カウントは実際には最大インデックスに 1 を加えたものとして解釈する必要があります。[ 6 ] さらに、2 種類の定数 (long と double) がテーブル内で 2 つの連続したスロットを占有しますが、2 番目のスロットは直接使用されることのない仮想インデックスです。
定数プール内の各項目(定数)の型は、先頭のバイトタグによって識別されます。このタグに続くバイト数とその解釈は、タグの値によって異なります。有効な定数型とそのタグ値は以下のとおりです。
整数定数型は、integer型とlong型の2種類のみです。高級言語で用いられるその他の整数型(boolean型、byte型、short型など)は、整数定数として表現する必要があります。
Java のクラス名は、完全修飾の場合、従来はドットで区切られ、「java.lang.Object」のようになります。しかし、低レベルのクラス参照定数では、代わりにスラッシュを使用する内部形式が使用され、「java/lang/Object」のようになります。
Unicode 文字列は、「UTF-8 文字列」という名称にもかかわらず、実際には Unicode 標準に従ってエンコードされているわけではありませんが、類似しています。違いは 2 つあります (詳細についてはUTF-8 をC0 80参照してください)。 1 つ目は、コード ポイント U+0000 が標準の 1 バイト エンコーディングではなく、2 バイト シーケンス (16 進数)としてエンコードされている00ことです。 2 つ目は、補助文字 ( U+10000 以上でBMP の外側にある文字) が UTF-8 を使用して直接エンコードされるのではなく、 UTF-16と同様のサロゲート ペア構造を使用してエンコードされていることです。この場合、2 つのサロゲートはそれぞれ UTF-8 で個別にエンコードされます。たとえば、U+1D11E は、ED A0 B4 ED B4 9E正しい 4 バイトの UTF-8 エンコーディングではなく、 6 バイト シーケンスとしてエンコードされますF0 9D 84 9E。