実行時におけるJava SE 9モジュールとクラスローダーの関連

Java SE 9のモジュール・システム(Jigsaw)はコンパイル時と実行時の両方で機能します。実行時には、Java SE 8以前から存在するクラスローダーの機構とうまく帳尻を合わせて、既存のアプリケーションを壊さないようにする必要があります。結果として、両者の関係は微妙で奇妙なものとなっています。

下記の図は、クラスローダー、モジュールその他の関連をIDEF1X記法で示したものです。

http://d.hatena.ne.jp/miyakawa_taku/files/2017-11-08_class_loaders_and_modules.png?d=.png

クラス、パッケージ、クラスローダー

これらの部品は、Java SE 8以前と同様に、Java SE 9でも機能します。

(1) クラスローダーがクラスを定義すると、そのクラスは、クラス名とクラスローダーにもとづいて、実行時パッケージに紐付けられます。

(2) 実行時パッケージは、パッケージ名と、パッケージ内のクラスを定義するクラスローダーの対によって指し示されます。

モジュール、モジュールローダー

(3) Java SE 9では、実行時パッケージは実行時モジュールに紐付きます。

(4) モジュールにはふたつの種類があります。名前付きモジュール *1 と無名モジュールです。

(5) ModuleLayer.defineModulesの呼び出しによってModuleLayerが作られると、引数として渡されたConfigurationにもとづいて、名前付きモジュール群が作られます。名前付きモジュール群はモジュールレイヤーに紐付けられます。

(6) 名前付きモジュールは、ModuleDescriptorにもとづくパッケージ群を持っていて、両者の関連は互いに不変です。

(7) 名前付きモジュールは、ModuleLayer.defineModulesメソッドで指定されたクラスローダーに紐付けられます。

同名のパッケージを含む複数の名前付きモジュールを、ひとつのクラスローダーに紐付けることはできません。パッケージは複数のモジュールにまたがれないためです。このような状況を防ぐため、ModuleLayer.defineModulesメソッドは不変条件をチェックして、違反があればLayerInstantiationExceptionを投げます。たとえば、クラスローダーがorg.example.Fooクラスを既に定義している場合、ModuleLayer.defineModulesメソッドは、このクラスローダーにorg.exampleパッケージを含む名前付きモジュールを紐付けられません。

(8) クラスローダーには、ひとつの無名モジュールが紐付いています。クラスローダーがクラスを定義するとき、そのパッケージが、クラスローダーに紐付けられたどのモジュールにも紐付けられていない場合、そのパッケージはクラスローダーの無名モジュールに紐付けられます。ここで、無名モジュールはどのモジュールレイヤーにも属さないことに注意してください。

クラスローダーとモジュールレイヤーの間の関連には、直接の制限はありません。たとえば、ひとつのクラスローダーが、複数のモジュールレイヤーにまたがってクラスを定義することも可能です (JVMS9 §5.3.6) 。ただし、そのような構成に実際上の利点はなさそうです。

*1:「名前付きモジュール」という用語は、ModuleDescriptorのJavadocで暗黙的に定義されています。