- クラスローダーはクラスファイルを見つけ、JVMにロードすることで、プログラムがそれを利用できるようにします。
- クラスは起動時ではなく、初めて使用されるときにロードされ、ローダーは毎回バイトコードを特定します。
- 組み込みのローダーは、上位へ委譲する親子関係(ブートストラップ、プラットフォーム、アプリケーション)を形成します。
- カスタムクラスローダーのおかげで、MinecraftのMODはクラスがロードされる際にゲームクラスをパッチすることができます.
クラスローダーは、Javaランタイムの一部であり、クラスファイルを見つけてJVMにロードし、プログラムが使用できるようにします。クラスはすべて起動時にロードされるわけではありません。JVMは、必要になったときに初めてロードし、クラスローダーがバイトコードを特定し、読み取り、JVMに渡す役割を担います。Minecraft Java Editionは、この仕組み上で動作しています.
クラスローダーが実際に何をするのか
クラスローダーは、クラス名を実行中のJVM内で使用可能なクラスに変換します。ある型を要求すると、ローダーは対応する.classバイトコードを検索し、JVMはその型をメモリに定義します。
この処理は3つのステップで行われます。ローダーは、名前付きクラスのバイトコードを見つけます。JVMはそれを検証し、リンクします。その後、クラスは使用できるようになります。このため、Javaプログラムはコンパイル時に言及しなかったコードを取り込むことができます。名前さえあれば、ローダーがそれを探し出すことができるからです。
ローダーの階層構造
クラスローダーは親チェーンで構成されており、そのほとんどが最初に親に問い合わせます。標準的なアプリケーションには、3つの組み込みローダーが積み重ねられています。
| ローダー | 読み込むもの |
|---|---|
| ブートストラップ | コアJavaランタイムクラス |
| プラットフォーム | コア外の標準ライブラリモジュール |
| アプリケーション | クラスパスからのプログラム独自のクラス |
アプリケーションローダーにクラスを要求された場合、通常は最初に上位に委譲します。親が読み込む機会を得て、親が読み込めない場合にのみ、子ローダーが試みます。これは委譲モデルと呼ばれ、プログラム全体でコア型の一貫性を保ちます。
クラスの同一性とカスタムローダー
クラスは、名前とそれを定義したローダーによって識別されます。同じ名前のクラスを複数のローダーがロードしても、JVMはそれらを異なる型として扱います。これは些細なことのように思えるかもしれませんが、クラスローダーが強力である理由の根幹をなしています。
プログラムは独自のクラスローダーを定義できます。カスタムローダーは、JARファイル、ネットワーク、生成されたバイト配列、さらには途中で変換されたバイトコードなど、どこからでもバイトコードを読み込むことができます。これが、プラグインシステム、アプリケーションサーバー、およびmodフレームワークが、ホストプログラムがビルド時に知らなかったコードをロードする方法です。
Minecraft modにとってなぜこれが重要なのか
modはカスタムクラスローディングによって存在します。Minecraftのmodローダーは、ゲームを独自のクラスローダーで起動するため、ゲームクラスがロードされる際にそれらを見たり変更したりできます。そのフックポイントでバイトコードパッチングが行われます。
ローダーがディスクとJVMの間に位置することで、JVMがクラスを定義する直前にクラスを変換できます。modはゲームメソッドを書き換えたり、新しい動作を注入したり、フィールドを追加したりできます。これは、ディスク上のゲームの修正コピーなしで実現できます。JVMが最終的に実行するクラスは、パッチされたものです。より広い状況におけるこの仕組みについては、Minecraft modローダーとは何ですか?を参照してください。
FAQ
初めて使用する際に、起動時ではありません。コードが型に初めて触れたとき、JVMはクラスローダーにその型を見つけて定義するように要求します。これは遅延ロードと呼ばれます。
ローダーは、自身がクラスをロードする前に、親にロードを要求します。親チェーンは、同じ名前で同じ Java 型が二重にロードされるのを防ぐ、ブートストラップローダーまで続きます。
はい、異なるクラスローダーで定義されていれば可能です。JVMは、クラスの名前とそれを定義するローダーによってクラスを識別するため、別のローダーから読み込まれた同じ名前のクラスは、異なる型として区別されます。
ゲームクラスのロードとメモリ内へのパッチ適用を監視するためです。カスタムローダーは、JVMがクラスを定義する前にバイトコードを変換でき、これによりMODはディスク上のファイルを編集することなくゲームを変更できます。