Javaクラスファイルのライフスタイル

「UndertheHood」の別の記事へようこそ。先月の記事では、すべてのJavaプログラムがコンパイルされる抽象コンピューターであるJava仮想マシン(JVM)について説明しました。JVMに慣れていない場合は、この記事の前に先月の記事を読むことをお勧めします。この記事では、Javaクラスファイルの基本的な構造とライフスタイルを垣間見ることができます。

旅行に生まれる

Javaクラスファイルは、コンパイルされたJava用に正確に定義された形式です。Javaソースコードは、任意のJVMでロードおよび実行できるクラスファイルにコンパイルされます。クラスファイルは、JVMによってロードされる前にネットワーク上を移動する場合があります。

実際、Java対応のブラウザーを介してこの記事を読んでいる場合、記事の最後にあるシミュレーションアプレットのクラスファイルは、現在インターネットを介してコンピューターに飛んでいます。それらを聴きたい場合(そしてコンピューターにオーディオ機能がある場合)、次のボタンを押してください。

このアプレットを表示するには、Java対応のブラウザが必要です

彼らは楽しんでいるようですね。それは彼らの本質です。Javaクラスファイルは、うまく移動するように設計されています。プラットフォームに依存しないため、より多くの場所で歓迎されます。これらには、JVM用のコンパクトな命令セットであるバイトコードが含まれているため、簡単に移動できます。Javaクラスファイルは、世界中のJVMに到達するために、絶えず驚異的な速度でネットワークを介して圧縮されています。

クラスファイルには何が含まれていますか?

Javaクラスファイルには、JVMが1つのJavaクラスまたはインターフェイスについて知る必要があるすべてのものが含まれています。クラスファイルに表示される順序での主要なコンポーネントは、マジック、バージョン、定数プール、アクセスフラグ、このクラス、スーパークラス、インターフェイス、フィールド、メソッド、および属性です。

クラスファイルに格納されている情報の長さはさまざまです。つまり、クラスファイルをロードする前に情報の実際の長さを予測することはできません。たとえば、メソッドコンポーネントにリストされているメソッドの数は、ソースコードで定義されているメソッドの数に依存するため、クラスファイル間で異なる場合があります。このような情報は、実際の情報の前にサイズまたは長さを付けることにより、クラスファイルに編成されます。このように、クラスがJVMによってロードされるとき、可変長情報のサイズが最初に読み取られます。 JVMがサイズを認識すると、実際の情報を正しく読み取ることができます。

情報は通常、連続する情報の間にスペースやパディングなしでクラスファイルに書き込まれます。すべてがバイト境界に配置されます。これにより、クラスファイルを小柄に保つことができるため、ネットワーク上を飛行するときに空力的になります。

クラスファイルコンポーネントの順序は厳密に定義されているため、JVMは、クラスファイルをロードするときに、何を期待し、どこで期待するかを知ることができます。たとえば、すべてのJVMは、クラスファイルの最初の8バイトにマジック番号とバージョン番号が含まれていること、定数プールが9バイト目から始まること、およびアクセスフラグが定数プールの後に続くことを認識しています。ただし、定数プールは可変長であるため、定数プールでの読み取りが完了するまで、アクセスフラグの正確な所在はわかりません。定数プールでの読み取りが完了すると、次の2バイトがアクセスフラグになることがわかります。

マジックとバージョン番号

すべてのクラスファイルの最初の4バイトは常に0xCAFEBABEです。このマジックナンバーにより、Javaクラスファイルの識別が容易になります。これは、非クラスファイルが同じ最初の4バイトで始まる可能性が低いためです。この番号は、ファイル形式の設計者が帽子から引き出すことができるため、マジックと呼ばれます。唯一の要件は、現実の世界で遭遇する可能性のある別のファイル形式でまだ使用されていないことです。元のJavaチームの主要メンバーであるPatrickNaughtonによると、マジックナンバーは「Javaという名前がこの言語に関連して発声されるずっと前に選ばれました。私たちは楽しく、ユニークで、覚えやすいものを探していました。それはPeet's Coffeeのかわいいバリスタへの斜めの言及であるOxCAFEBABEが、Javaという名前の前兆となったのは偶然の一致です。」

クラスファイルの次の4バイトには、メジャーバージョン番号とマイナーバージョン番号が含まれています。これらの番号は、特定のクラスファイルが準拠するクラスファイル形式のバージョンを識別し、JVMがクラスファイルがロード可能であることを確認できるようにします。すべてのJVMには、ロードできる最大バージョンがあり、JVMはそれ以降のバージョンのクラスファイルを拒否します。

一定のプール

クラスファイルは、そのクラスまたはインターフェイスに関連付けられた定数を定数プールに格納します。プール内で戯れるのが見られる可能性のある定数には、リテラル文字列、最終変数値、クラス名、インターフェイス名、変数名と型、およびメソッド名と署名があります。メソッドシグネチャは、その戻り値の型と引数の型のセットです。

定数プールは、可変長要素の配列として編成されます。各定数は、配列内の1つの要素を占めます。クラスファイル全体で、定数は配列内での位置を示す整数インデックスによって参照されます。最初の定数のインデックスは1、2番目の定数のインデックスは2などです。定数プール配列の前には配列サイズがあるため、JVMはクラスファイルをロードするときに予想される定数の数を認識します。

定数プールの各要素は、配列内のその位置にある定数のタイプを指定する1バイトのタグで始まります。JVMがこのタグを取得して解釈すると、JVMはタグの後に何があるかを認識します。たとえば、タグが定数が文字列であることを示している場合、JVMは次の2バイトが文字列の長さであると想定します。この2バイトの長さに続いて、JVMは文字列の文字を構成するバイト数の長さを見つけることを想定しています。

この記事の残りの部分では、定数プール配列のn番目の要素をconstant_pool [n]と呼ぶことがあります。これは、定数プールが配列のように編成されている限り意味がありますが、これらの要素のサイズとタイプは異なり、最初の要素のインデックスは1であることに注意してください。

アクセスフラグ

定数プールの後の最初の2バイト、アクセスフラグは、このファイルがクラスまたはインターフェイスを定義するかどうか、クラスまたはインターフェイスがパブリックか抽象か、および(クラスであり、インターフェイスではない場合)クラスかどうかを示します。最終です。

このクラス

次の2バイト、このクラスコンポーネントは、定数プール配列へのインデックスです。このクラスによって参照される定数constant_pool [this_class]には、1バイトのタグと2バイトの名前インデックスの2つの部分があります。タグはCONSTANT_Classと等しくなります。これは、この要素にクラスまたはインターフェイスに関する情報が含まれていることを示す値です。Constant_pool [name_index]は、クラスまたはインターフェースの名前を含む文字列定数です。

このクラスのコンポーネントは、定数プールの使用方法の一見を提供します。このクラス自体は、定数プールへの単なるインデックスです。JVMがconstant_pool [this_class]を検索すると、タグを使用して自身をCONSTANT_Classとして識別する要素が見つかります。JVMは、CONSTANT_Class要素が常に1バイトのタグに続く名前インデックスと呼ばれる定数プールへの2バイトのインデックスを持っていることを知っています。したがって、constant_pool [name_index]を検索して、クラスまたはインターフェイスの名前を含む文字列を取得します。

スーパークラス

このクラスコンポーネントに続くのはスーパークラスコンポーネントで、定数プールへの別の2バイトのインデックスです。Constant_pool [super_class]は、このクラスの子孫であるスーパークラスの名前を指すCONSTANT_Class要素です。

インターフェイス

インターフェイスコンポーネントは、ファイルで定義されたクラス(またはインターフェイス)によって実装されたインターフェイスの数の2バイトカウントで始まります。すぐ後に続くのは、クラスによって実装された各インターフェイスの定数プールへの1つのインデックスを含む配列です。各インターフェイスは、インターフェイスの名前を指す定数プール内のCONSTANT_Class要素によって表されます。

田畑

fieldsコンポーネントは、このクラスまたはインターフェイスのフィールド数の2バイトカウントで始まります。フィールドは、クラスまたはインターフェイスのインスタンスまたはクラス変数です。カウントに続いて、フィールドごとに1つずつ、可変長構造の配列があります。各構造体は、フィールドの名前、タイプ、および最終変数の場合はその定数値など、1つのフィールドに関する情報を明らかにします。一部の情報は構造自体に含まれ、一部は構造が指す定数プールの場所に含まれます。

リストに表示されるフィールドは、ファイルで定義されているクラスまたはインターフェイスによって宣言されたフィールドのみです。スーパークラスまたはスーパーインターフェイスから継承されたフィールドはリストに表示されません。

メソッド

メソッドコンポーネントは、クラスまたはインターフェイス内のメソッド数の2バイトカウントで始まります。このカウントには、このクラスによって明示的に定義されているメソッドのみが含まれ、スーパークラスから継承される可能性のあるメソッドは含まれません。メソッド数に続いて、メソッド自体があります。

各メソッドの構造には、メソッド記述子(戻り値の型と引数リスト)、メソッドのローカル変数に必要なスタックワードの数、メソッドのオペランドに必要なスタックワードの最大数など、メソッドに関するいくつかの情報が含まれています。スタック、メソッドによってキャッチされた例外のテーブル、バイトコードシーケンス、および行番号テーブル。

属性

後部を表示するのは、ファイルによって定義された特定のクラスまたはインターフェースに関する一般的な情報を提供する属性です。属性セクションには、属性数の2バイトのカウントがあり、その後に属性自体が続きます。たとえば、1つの属性はソースコード属性です。このクラスファイルがコンパイルされたソースファイルの名前が表示されます。JVMは、認識しない属性を黙って無視します。

ロードされる:JVM宛先に到達するクラスファイルのシミュレーション

以下のアプレットは、クラスファイルをロードするJVMをシミュレートします。シミュレーションでロードされるクラスファイルは、次のJavaソースコードを指定してjavacコンパイラによって生成されました。

class Act {public static void doMathForever(){int i = 0; while(true){i + = 1; i * = 2; }}}

上記のコードスニペットは、JVMに関する先月の記事からのものです。これは、先月の記事のEternalMathアプレットによって実行されたのと同じdoMathForever()メソッドです。このコードを選択したのは、それほど複雑ではない実際の例を提供するためです。コードは実際にはあまり役に立たないかもしれませんが、実際のクラスファイルにコンパイルされます。このファイルは、以下のシミュレーションによってロードされます。

GettingLoadedアプレットを使用すると、クラス負荷シミュレーションを一度に1ステップずつ実行できます。途中の各ステップで、JVMによって消費および解釈されようとしている次のバイトチャンクについて読み取ることができます。 「ステップ」ボタンを押すだけで、JVMが次のチャンクを消費します。 「戻る」を押すと前の手順が元に戻り、「リセット」を押すとシミュレーションが元の状態に戻り、最初からやり直すことができます。

JVMは左下に表示され、クラスファイルAct.classを構成するバイトストリームを消費します。バイトは、右下のサーバーからの16進ストリーミングで表示されます。バイトは、サーバーとJVMの間で、一度に1チャンクずつ右から左に移動します。次の「ステップ」ボタンを押したときにJVMによって消費されるバイトのチャンクは赤で表示されます。これらの強調表示されたバイトは、JVMの上の大きなテキスト領域に記述されています。次のチャンクを超える残りのバイトは黒で表示されます。

テキスト領域のバイトの各チャンクを完全に説明しようとしました。したがって、テキスト領域には多くの詳細があり、最初にすべての手順をざっと読んで一般的なアイデアを取得してから、詳細を振り返ることができます。

ハッピークリック。

このアプレットを表示するには、Java対応のブラウザが必要です。

GettingLoadedのソースコードはこちらをクリックしてください。このアプレットを自分で実行するには、このアプレットがサーバーから取得する2つのファイル、各ステップのテキストを含むASCIIファイルとAct.classファイル自体も必要です。Flying Class Filesオーディオアプレットのソースコードについては、ここをクリックしてください。

ENDNOTE:小さな活字:「Javaクラスファイルのライフスタイル」記事Copyright(c)1996 BillVenners。全著作権所有。「GettingLoaded」アプレットCopyright(c)1996 Artima SoftwareCompany。全著作権所有。

:END_ENDNOTE

Bill Vennersは、Artima SoftwareCompanyの社長です。Artimaを通じて、彼はカスタムソフトウェア開発とコンサルティングを行っています。

このトピックの詳細

  • Sunの公式用語であるJava仮想マシン仕様。

    //java.sun.com/1.0alpha3/doc/vmspec/vmspec_1.html

  • それが出たとき、Javaの一部であるTimLindholmとFrankYellin(ISBN 0-201-63452-X)による本The Java Virtual Machine Specification、// www.aw.com/cp/lindholm-yel​​lin.html Addison-Wesleyのシリーズ(//www.aw.com/cp/javaseries.html)は、おそらく最高のJVMリソースになるでしょう。
  • クラスファイル形式とバイトコードベリファイアについて説明しているJava仮想マシン仕様の第4章のドラフトは、JavaSoftから取得できます。

    //java.sun.com/java.sun.com/newdocs.html

このストーリー「Javaクラスファイルのライフスタイル」は、もともとJavaWorldによって公開されました。