大文字と小文字を区別しない同じ名前の 2 つのパブリック Java クラスを異なるディレクトリに書き込むと、両方のクラスが実行時に使用できなくなります。a
(いくつかのバージョンの HotSpot JVM を使用して、Windows、Mac、および Linux でこれをテストしました。同時に使用できる JVM が他にA
あるとしても驚かないでしょう。)
// lowercase/src/testcase/a.java
package testcase;
public class a {
public static String myCase() {
return "lower";
}
}
// uppercase/src/testcase/A.java
package testcase;
public class A {
public static String myCase() {
return "upper";
}
}
上記のコードを含む 3 つの eclipse プロジェクトは、私の Web サイト から入手できます。
myCase
試してみると、次のように両方のクラスを呼び出します。
System.out.println(A.myCase());
System.out.println(a.myCase());
タイプチェッカーは成功しますが、上記のコードで生成されたクラス ファイルを実行すると、次のようになります。
スレッド「メイン」の例外 java.lang.NoClassDefFoundError: testcase/A (間違った名前: testcase/a)
Java では、名前は一般に大文字と小文字が区別されます。一部のファイル システム (Windows など) では大文字と小文字が区別されないため、上記の動作が発生することに驚きはありませんが、間違っているようです。残念ながら、Java の仕様は、どのクラスが表示されるかについて、奇妙に非コミットです。Java 言語仕様 (JLS)、Java SE 7 Edition (セクション 6.6.1、166 ページ) は次のように述べています。
クラスまたはインターフェイス型が public と宣言されている場合、それが宣言されているコンパイル ユニット (§7.3) が監視可能であれば、任意のコードからアクセスできます。
セクション 7.3 で、JLS はコンパイル単位の可観測性を非常にあいまいな用語で定義しています。
定義済みパッケージ java とそのサブパッケージ lang および io のすべてのコンパイル ユニットは、常に監視可能です。他のすべてのパッケージの場合、ホスト システムはどのコンパイル ユニットが監視可能かを判断します。
Java 仮想マシン仕様も同様にあいまいです(セクション 5.3.1):
次の手順を使用してロードし、それによってブートストラップ クラス ローダーを使用して [バイナリ名] N で示される非配列クラスまたはインターフェイス C を作成します [...] それ以外の場合、Java 仮想マシンは引数 N をメソッドの呼び出しに渡します。ブートストラップ クラス ローダーを使用して、プラットフォームに依存する方法で C の表現とされるものを検索します。
これらはすべて、重要度の高い順に次の 4 つの質問につながります。
- すべての JVM で、デフォルトのクラスローダーによってどのクラスがロード可能であるかについて保証はありますか? つまり、java.lang と java.io 以外のクラスをロードしない、有効であるが縮退した JVM を実装できますか?
- 保証がある場合、上記の例の動作は保証に違反していますか (つまり、動作はバグですか)?
- HotSpot
a
をA
同時にロードする方法はありますか? カスタム クラス ローダーの作成は機能しますか?