CLASSPATH
および -classpath
の変更
-Xbootclasspath
、
-bootclasspath
oldjava
CLASSPATH
を使わなくなった appletviewer
-sourcepath
このドキュメントは、JDK 1.1 から JDK 1.2 で変更されたツールのコマンド行オプションに関して、特に重要な変更内容の概要を説明するもので、すでに JDK 1.1 ツールのコマンド行オプションに精通しているユーザを対象としています。
JDK1.2 のオプションでは、できる限り JDK1.1 のオプションに対する下位互換性を保つようにしてあります。このドキュメントの目的は、変更点、および変更理由の概略を説明することです。変更の理由を理解して、新しい機能のより効果的な利用に役立ててください。
このドキュメントでは、Java API の仕様で指定されているように、
java.lang.String
などの Java プラットフォームに属するクラスを指して、「Java プラットフォームクラス」という用語を使います。これらのクラスは、classes.zip
またはrt.jar
内にあります。また、CLASSPATH
および-classpath
によって設定される検索パスを指して、「クラスパス」という用語を使います。ただし、-classpath
は、1.1 と 1.2 では意味が異なっています。このドキュメント内で紹介する例は Solaris 向けですが、スラッシュとプロンプトを適切に変更すれば、Windows にも同様に適用できます。
CLASSPATH
および -classpath
の変更クラスパスにはデフォルト値があり、
-classpath
またはCLASSPATH
を使って設定できます。1.1 では、クラスパスは次のように機能しました。この
- クラスパスのデフォルト - クラスパスのデフォルト値は、(1) Java プラットフォームクラスが格納されているパス (
classes.zip
またはrt.jar
)、および (2) 現在作業中のディレクトリ (.
) であるCLASSPATH
- 環境変数CLASSPATH
が設定された場合、クラスパスは、(1) デフォルトと同様にclasses.zip
またはrt.jar
を含み、その他に (2) 現在作業中のディレクトリの代わりに新しく設定された値を含む [注 1 を参照]-classpath
- オプション-classpath <path>
が使われた場合、<path>
に (1)classes.zip
またはrt.jar
、および (2) アプリケーションクラスの両方を明示的に含める必要があった-classpath
の動作は、ユーザがclasses.zip
へのパスを入力する必要があったため、問題になる可能性がありました。C:> java -classpath C:¥jdk-path¥lib¥classes.zip;¥app¥classes Application問題になる可能性とは、この動作は本質的にエラー発生の可能性を含んでいるということです。つまり、ユーザの責任において、同じバージョンの JDK のjava
コマンドとclasses.zip
を使う必要がありました。開発チームでも、1.1.4 のjava
で 1.1.3 のclasses.zip
を実行する箇所の問題のデバッグに努めましたが、ネイティブメソッドが一致しないため不可能でした。1.2 の
-classpath
オプションは、1.2 のCLASSPATH
環境変数と同じ意味を持つので、Java プラットフォームクラスへのパスを入力する必要がなくなり、便利になりました。C:> java -classpath C:¥app¥classes Application開発者によっては、
println
文を追加してクラスの動作方法がわかるようにするために、java¥util¥Vector.class
などの個々の Java プラットフォームクラスを一時的に修正したい場合があります。1.2 では、1.1 でのように-classpath
オプションを使って Java プラットフォームクラスへのパスを設定することはできません。このような場合、1.2 では-Xbootclasspath
オプションを使う必要があります。注 1 - 上記の箇条書きに反して、
CLASSPATH
環境変数にclasses.zip
へのパスを明示的に指定しているユーザもいますが、これはまったく必要ありません。
前のセクションでは、JDK 1.1 にはクラスの検索に使う検索パスが 1 つあり、その値は
-classpath
オプション、またはCLASSPATH
環境変数によって設定できることを示しました。JDK 1.2 では、クラスの検索に使う検索パスは 3 つあります。
java
が最初にクラスを検索する場所は、ブートストラップクラスパスです。このパスの値は、System.getProperty("sun.boot.class.path")
を呼び出して調べることができます。なお、接頭辞sun.
は、少なくとも現在のところは、このプロパティが Sun の実装特有のものであることを示します。java
が次にクラスを検索する場所は、拡張機能ディレクトリです。ディレクトリの一覧は、System.getProperty("java.ext.dirs")
を呼び出して調べることができます。java
が 3 番目にクラスを検索する場所は、アプリケーションクラスパスです。このパスの値は、System.getProperty("java.class.path")
を呼び出して調べることができます。項目 2 の新しい「拡張機能ディレクトリ」機能については、「javac」 および 「Java 拡張機能機構」を参照してください。
1.2 では、
-classpath
オプションとともに指定する引数は、「アプリケーションクラスパス」の値で、アプリケーションを構成するクラスのパスを含んでいる必要があります。「ブートストラップクラスパス」は、rt.jar
というファイルに含まれた Java プラットフォームクラスへのパスを含みます。これについては、次のセクションで説明します。
-Xbootclasspath
、-bootclasspath
注 - オプションの先頭の「X」の意味については、「標準オプションと非標準オプション」を参照してください。-Xbootclasspath
- すでに説明したとおり、「ブートストラップクラスパス」は、rt.jar
に含まれた Java プラットフォームクラスへのパスを含みます。Java プラットフォームクラスが見つかった位置をオーバーライドする必要がある場合は、-Xbootclasspath
オプションを使わなければなりません。これは、-classpath
がこの機能を提供していた 1.1 からの大きな変更点です。次に例を示します。C:> java -Xbootclasspath;C:¥my¥bootclasses;C:¥jre¥lib¥rt.jar MyApplicationこの例では、
java
コマンドで-Xbootclasspath
によって提供されたパスを探し、Java プラットフォームクラスを見つけます。rt.jar
内を検索する前に、まず、C:¥my¥bootclasses
ディレクトリを検索します。java¥util¥Vector.class
にデバッグ文を追加する場合は、修正したクラスファイルをC:¥my¥bootclasses
の下に置きます。この修正版のファイルが最初に見つけられ、検索が終了し、修正版がロードされます。
-bootclasspath
- さらに、javac
は、コンパイルを行うプラットフォームクラスの変更に使用できる同様のオプション-bootclasspath
をサポートしています。このオプションは、バグが修正された 1.2 の javac を利用して 1.1 のアプリケーションをコンパイルするときにもっとも便利です。詳しい方法については、このオプションの説明を参照してください。以下は、両方のオプションに関連した注意事項です。
- Java プラットフォームクラスのオーバーライドを避ける - JRE 再配布ライセンスでは、
rt.jar
の一部を置き換えることは許可されていません。アプリケーションとともに JRE を再配布する際は、-Xbootclasspath
オプションを使ってrt.jar
の一部をオーバーライドすることはできません。再配布時にブートクラスパス上にアプリケーションを置く必要がある場合は、oldjava
コマンドを使うことをお勧めします。oldjava
を使わない場合は、変更されていないrt.jar
およびi18n.jar
(省略可能) を、-Xbootclasspath 内のアプリケーションクラスより前の位置に記述する必要があります。# If app needs to be deployed on -Xbootclasspath, then use: C:> java -Xbootclasspath;C:¥jre¥lib¥rt.jar;C:¥app¥classes Application # instead of accidentally overriding rt.jar: C:> java -Xbootclasspath;C:¥app¥classes;C:¥jre¥lib¥rt.jar Application- クラスパス検索の実装 - これらのパスが
java
の実装によってどのように結び付けられるかについて簡単に説明します。1.2 では、「親」クラスローダの概念を導入しています。1.2 では、正常に動作するクラスローダは、クラスローダ自体の機構 (検索するよう要求されたパスなど) を使ってクラスを検索する前に、その親がそのクラスをロードできるかどうかをチェックします。
Java Runtime には、次の 3 つのクラスローダがあります。親クラスローダは、子の上に示されています。
ブートストラップクラスローダ | 拡張機能クラスローダ | アプリケーションクラスローダブートストラップクラスローダは、ブートストラップクラスパス上でだけクラスを検索し、ほかのパス上では検索しません。同様に、拡張機能クラスローダは、拡張機能ディレクトリからロードされた拡張機能で検索を行い、アプリケーションクラスローダは、アプリケーションクラスパス上でだけ検索を行います。たとえば、次のコマンドを使ってアプリケーションを起動するとします。
C:> java -classpath C:¥my¥classes MyApplicationこのコマンドにより、一連のステップが発生し、それぞれのクラスローダに順にアプリケーションクラスをロードする機会が与えられます。最初に、このjava
コマンドは、アプリケーションクラスローダ (-classpath
値を使うクラスローダ) にMyApplication
をロードするように問い合わせます。しかし、アプリケーションクラスローダは、このクラスをロードする代わりに、親の拡張機能クラスローダに、このクラスをロードするように問い合わせます。拡張機能クラスローダも同様に、その親であるブートストラップクラスローダにこのクラスをロードするように問い合わせます。ブートストラップクラスローダは、Virtual Machine 内に構築されており、親はありません。そこでブートストラップクラスローダがブートストラップクラスパスからこのクラスをロードしようとします。しかし、MyApplication
を見つけられないので (-Xbootclasspath
を使わずデフォルトパスのままにしたため)、ブートストラップクラスローダは拡張機能クラスローダにクラスのロードを許可しますが、拡張機能クラスローダもこのクラスを見つけることができません (-Djava.ext.dirs
を使わずデフォルトパスのままにしたため)。最終的に、アプリケーションクラスローダがC¥my¥classes¥MyApplication.class
を見つけ、ロードします。クラスの検索が「最初にブートストラップ、次に拡張機能、最後にアプリケーション」という順番で行われるのは、このような親子関係があるためです。詳細は、「Java 拡張機能機構」を参照してください。
oldjava
oldjava
CLASSPATH
を使わなくなった appletviewer
appletviewer
は JDK 1.1 ではCLASSPATH
環境設定を無視しませんでしたが、JDK 1.2 では無視します。これは、思い切った変更のようですが、アプレットのテスト時には必要なセマンティクスです。JDK 1.1 では動作し、JDK 1.2 では動作しなくなった例を考えてみます。
.html
ファイルを.class
ファイルとは別の場所に置いたとします。JDK 1.1 では、CLASSPATH
を.class
ファイルに設定でき、appletviewer
はそれを認識しました。# Foo.class and foo.html are in different directories. C:> dir ¥home¥user¥htmls ¥home¥user¥classes C:¥home¥user¥classes: Foo.class C:¥home¥user¥htmls: foo.html # Foo.class is NOT in applet's codebase: C:> type ¥home¥user¥htmls¥foo.html <applet code=Foo height=100 width=100></applet> # Can an applet use a class outside its codebase? C:> set CLASSPATH=C:¥home¥user¥classes # Works in 1.1. C:> ¥1.1.7¥bin¥appletviewer ¥home¥user¥htmls¥foo.html # ClassNotFoundException in 1.2! C:> ¥1.2¥bin¥appletviewer ¥home¥user¥htmls¥foo.htmlこのような正常に見える動作を変更したのは、JDK の
appletviewer
とは異なり、CLASSPATH
が優先されないブラウザでアプレットが実行された場合、1.2 を使った場合と同じ問題が発生するためです。アプレットによって参照されるクラスは、次のどちらかである必要があります。アプレットのユーザが
- ブラウザ内に存在する
java.lang.String
などの Java プラットフォームクラス- アプレットの
codebase
からダウンロード可能なクラスCLASSPATH
を設定することを前提にはできません。たとえ、ユーザがCLASSPATH
を設定したとしても、ブラウザによって無視される可能性もあります。このため、1.2 では、appletviewer
はブラウザと同じことを行います。
CLASSPATH
を優先する 1.1 のappletviewer
には長所もありました。たとえば、電子メール関連の機能を提供するmailx.jar
などのサードパーティのライブラリを取得してCLASSPATH
上に配置すると、アプレットでmailx.jar
内のクラスを参照できたことです。JDK 1.2 で同じ便宜性を保つためには、Java 拡張機能機構の使用をお勧めします。拡張機能機構は、「開発」時だけのソリューションであるCLASSPATH
とは異なり、配置用のソリューションです。
1.2 では、
-X
という接頭辞が付いているオプションと付いていないオプションがあります。1.1 では、Virtual Machine の起動ヒープサイズを 10M バイトに設定する必要があった場合、次のように指定しました。C:> java -ms10m Application1.2 では、
-X
を付けて同じオプションを表現することが推奨されています。C:> java -Xms10m Applicationこの目的は、1.2 では、すべての Virtual Machine に適用できるオプションと、特定の Virtual Machine の実装に特有のオプションとを区別することです。すべての Virtual Machine でクラスパスの設定が可能であることを前提としていますが、すべての Virtual Machine で初期ヒープサイズをサポートすることは前提にできません。
コンパイラおよび Virtual Machine のベンダーが同じ標準オプションをサポートするようになり、最終的には、コンパイラを交換しても Makefile を変更する必要がなくなり、スクリプトを使って起動するサーバアプリケーション用の Virtual Machine を交換してもスクリプトを修正する必要がなくなります。
下位互換性維持のために、1.2 の
java
起動ツールは、内部で-ms10m
を-Xms10m
に翻訳するので、古い-ms10m
オプションを使うこともできますが、新しい構文を使うことをお勧めします。現時点の標準オプションの一覧を表示するには、次のように入力します。
C:> java -help C:> javac -help現時点の非標準オプションの一覧を表示するには、次のように入力します。
C:> java -X C:> javac -Xベンダーの方々へ -- この標準と非標準のコマンド行オプションの区分は、規格適合要件とは別の問題です。前述したように、将来的に標準オプションがオプションの事実上の規格になった場合に、ユーザの作業が楽になるようにするためのものです。
-sourcepath
1.1 では、javac
およびjavadoc
は、ソースファイルとクラスファイルのどちらも、CLASSPATH
環境変数に指定されたパス内で検索していました。たとえば、foo¥bar¥FooBar.java
をコンパイルし、クラスFooBar
がHelper
クラスに依存しているとします。javac は、CLASSPATH 内でソースファイルHelper.java
の検索を試みます。C:> dir ¥tmp¥foo¥bar¥*.java ¥tmp¥foo¥bar¥FooBar.java ¥tmp¥foo¥bar¥Helper.java # Error because javac can't find Helper.class or Helper.java C:> ¥1.1.7¥bin¥javac ¥tmp¥foo¥bar¥FooBar.java ¥tmp¥foo¥bar¥FooBar.java:3: Superclass foo.bar.Helper of ... not found. C:> set CLASSPATH=¥tmp # Works because javac snooped in CLASSPATH for source files C:> ¥1.1.7¥bin¥javac ¥tmp¥foo¥bar¥FooBar.java1.2 でも、-sourcepath <path>
オプションを含めないと、これらのツールはCLASSPATH
内でソースファイルを検索します。-sourcepath <path>
オプションを含める場合、ソースファイルは<path>
内でだけ検索され、CLASSPATH
内では検索されません。C:> set CLASSPATH=¥tmp # This still works in 1.2: C:> ¥1.2¥bin¥javac ¥tmp¥foo¥bar¥FooBar.java # But it doesn't work if you use -sourcepath C:> ¥1.2¥bin¥javac -sourcepath . ¥tmp¥foo¥bar¥FooBar.java ¥tmp¥foo¥bar¥FooBar.java:3: Superclass foo.bar.Helper ... not found.