javac [ options ] [ sourcefiles ] [ classes ] [ @argfiles ]
引数は順不同です。
options
sourcefiles
classes
@argfiles
-J
オプションは指定できません。javac ツールは、Java プログラミング言語で記述されたクラスとインタフェースの定義を読み取り、バイトコードのクラスファイルにコンパイルします。また、Java ソースファイルおよびクラス内の注釈の処理も行います。
ソースコードのファイル名を javac に渡すには、次の 2 つの方法があります。
ソースコードのファイル名は .java
拡張子を、クラスのファイル名は .class
拡張子を持っていなければなりません。また、ソースファイルとクラスファイルのどちらも、該当するクラスに対応するルート名を持っていなければなりません。たとえば、MyClass
という名前のクラスは、MyClass.java
という名前のソースファイルに記述します。このソースファイルは、MyClass.class
という名前のバイトコードクラスファイルにコンパイルされます。
内部クラスが定義されていると、追加のクラスファイルが生成されます。これらのクラスファイルの名前は、MyClass$MyInnerClass.class
のように、外部クラス名と内部クラス名を組み合わせたものになります。
ソースファイルは、パッケージツリーを反映したディレクトリツリーに配置する必要があります。たとえば、すべてのソースファイルを /workspace に置いている場合、com.mysoft.mypack.MyClass
のソースコードは /workspace/com/mysoft/mypack/MyClass.java にある必要があります。
デフォルトでは、コンパイラは、各クラスファイルを対応するソースファイルと同じディレクトリに置きます。別の出力先ディレクトリを指定するには、-d を使用します (このあとの「オプション」を参照)。
コンパイラには、現在の開発環境でサポートされており、将来のリリースでもサポートされる標準オプションのセットがあります。これ以外の非標準オプションは、現在の仮想マシンおよびコンパイラの実装に固有のオプションで、将来に変更される可能性があります。非標準オプションは、-X で始まります。
com.mypackage.MyClass
であると、クラスファイルは /home/myclasses/com/mypackage/MyClass.class
になります。EUC-JP and UTF-8
など) を指定します。-encoding が指定されていない場合は、プラットフォームのデフォルトコンバータが使われます。ext
ディレクトリの位置をオーバーライドします。directories 変数は、コロンで区切ったディレクトリのリストです。指定したディレクトリ内の各 JAR アーカイブから、クラスファイルが検索されます。見つかったすべての JAR アーカイブが自動的にクラスパスの一部になります。com.mypackage.MyClass
であった場合、そのソースファイルは /home/mysrc/com/mypackage/MyClass.java
内に格納されます。デフォルトでは、クラスのコンパイルは、javac が添付されているプラットフォームのブートストラップクラスおよび拡張機能クラスに対して行われます。ただし、javac は、異なる Java プラットフォームに実装されたブートストラップクラスおよび拡張機能クラスに対してコンパイルを行うクロスコンパイルもサポートしています。クロスコンパイルを行う場合は、-bootclasspath および -extdirs を使うことが重要です。このあとの「クロスコンパイルの例」を参照してください。
-target のデフォルトは、次のように -source の値によって決まります。
System.err
に送られます。SOURCE
の保存ポリシーを使って宣言された注釈に任意の注釈プロセッサがアクセスできるようにしたい場合は、-Xprefer:source を使用してください。-Xlint:name オプションを使って警告 name を有効にします。name は次のいずれかの警告名です。同様に、-Xlint:-name オプションを使って警告 name を無効にできます。
String s = (String)"Hello!"
java.util.Date myDate = new java.util.Date(); int currentDay = myDate.getDay();メソッド
java.util.Date.getDay
は、JDK 1.1 以降は推奨されていません。
@deprecated
Javadoc コメントでドキュメント化されているが、@Deprecated
注釈が付いていない項目について警告します。たとえば、
/** * @deprecated As of Java SE 7, replaced by {@link #newMethod()} */ public static void deprecatedMethood() { } public static void newMethod() { }
int divideByZero = 42 / 0;
if
文のあとが空の文であることを警告します。たとえば、
class E { void m() { if (true) ; } }
switch (x) { case 1: System.out.println("1"); // No break statement here. case 2: System.out.println("2"); }このコードのコンパイル時に -Xlint:fallthrough フラグが使用されていた場合、コンパイラは該当するケースの行番号とともに、fall-through ケースの可能性があることを示す警告を発行します。
finally
節について警告します。たとえば、
public static int m() { try { throw new NullPointerException(); } catch (NullPointerException e) { System.err.println("Caught NullPointerException."); return 1; } finally { return 0; } }この例では、コンパイラは
finally
ブロックに関する警告を生成します。このメソッドが呼び出されると、値 1
ではなく 0
が返されます。finally
ブロックは、try
ブロックが終了すると必ず実行されます。この例では、catch
に制御が移されると、メソッドは終了します。ただし、finally
ブロックは実行される必要があるため、制御がすでにこのメソッドの外部に移されていても、このブロックは実行されます。
public class ClassWithVarargsMethod { void varargsMethod(String... s) { } }
public class ClassWithOverridingMethod extends ClassWithVarargsMethod { @Override void varargsMethod(String[] s) { } }コンパイラは次のような警告を生成します。
ClassWithVarargsMethod.varargsMethod
では、コンパイラは varargs の仮パラメータ String... s
を仮パラメータ String[] s
に (配列) 変換しますが、この配列はメソッド ClassWithOverridingMethod.varargsMethod
の仮パラメータと一致します。その結果、この例ではコンパイルが行われます。
@SuppressWarnings
注釈では抑制できません。たとえば、
javac -Xlint:path -classpath /nonexistentpath Example.java
AnnoProc.java
:
import java.util.*; import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; @SupportedAnnotationTypes("NotAnno") public class AnnoProc extends AbstractProcessor { public boolean process(Set<? extends TypeElement> elems, RoundEnvironment renv) { return true; } public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); } }ソースファイル
AnnosWithoutProcessors.java
:
@interface Anno { } @Anno class AnnosWithoutProcessors { }次のコマンドは、注釈プロセッサ
AnnoProc
をコンパイルしたあと、ソースファイル AnnosWithoutProcessors.java
に対してこの注釈プロセッサを実行します。
% javac AnnoProc.java % javac -cp . -Xlint:processing -processor AnnoProc -proc:only AnnosWithoutProcessors.javaソースファイル
AnnosWithoutProcessors.java
に対して注釈プロセッサを実行すると、コンパイラは次の警告を生成します。AnnosWithoutProcessors
クラスで定義および使用されている注釈の名前を Anno
から NotAnno
に変更します。
rawtypes
警告が生成されます。
void countElements(List l) { ... }次の場合は、
rawtypes
警告が生成されません。
void countElements(List<?> l) { ... }
List
は raw 型です。ただし、List<?>
はアンバウンド形式のワイルドカードのパラメータ化された型です。List
はパラメータ化されたインタフェースなので、必ずその型引数を指定するようにしてください。この例では、List
の仮引数はアンバウンド形式のワイルドカード (?
) を使用してその仮型パラメータとして指定されています。つまり、countElements
メソッドは List
インタフェースの任意のインスタンス化を受け入れることができます。
serialVersionUID
定義が直列化可能クラスにないことを警告します。たとえば、
public class PersistentTime implements Serializable { private Date time; public PersistentTime() { time = Calendar.getInstance().getTime(); } public Date getTime() { return time; } }コンパイラで次のような警告が生成されます。
serialVersionUID
という名前のフィールドを明示的に宣言しない場合、直列化ランタイムは「Java(TM) オブジェクト直列化仕様」で説明されているように、クラスのさまざまな側面に基づいて、クラスの serialVersionUID
のデフォルト値を計算します。ただし、すべての直列化可能クラスが serialVersionUID
値を明示的に宣言することを強くお勧めします。これは、デフォルトの serialVersionUID
の計算が、コンパイラの実装によって異なる可能性のあるクラスの詳細にきわめて影響を受けやすく、直列化復元中に予期しない InvalidClassExceptions
が発生する可能性があるためです。したがって、java コンパイラの実装が異なっても serialVersionUID
値の一貫性を確保にするには、直列化可能クラスが serialVersionUID
値を明示的に宣言しなければいけません。
class XLintStatic { static void m1() { } void m2() { this.m1(); } }コンパイラで次のような警告が生成されます。
warning: [static] static method should be qualified by type name, XLintStatic, instead of by an expressionこの問題を解決するために、次のように static メソッド
m1
を呼び出すことができます。
XLintStatic.m1();あるいは、
static
キーワードをメソッド m1
の宣言から削除することもできます。
try
ブロックの使用に関する問題について警告します。たとえば、try
文で宣言されたリソース ac
が使用されていないため、次の文に対して警告が生成されます。
try ( AutoCloseable ac = getResource() ) { // do nothing }
List l = new ArrayList<Number>(); List<String> ls = l; // unchecked warning型の消去中に、型
ArrayList<Number>
および List<String>
はそれぞれ ArrayList
および List
になります。ls
にはパラメータ化された型 List<String>
が指定されています。l
によって参照される List
が ls
に代入されると、コンパイラは未検査警告を生成します。コンパイラは、l
が List<String>
型を参照するかどうか (実際には参照しない) をコンパイル時に判断できません。また、JVM が実行時にそれを判断できないこともわかっています。その結果、ヒープ汚染が発生します。List
オブジェクト l
(その static 型は List<Number>
) が別の List
オブジェクト ls
(異なる static 型 List<String>
を持つ) に代入される場合です。しかし、コンパイラはこの代入をいまだに許可しています。この代入を許可する必要があるのは、ジェネリクスをサポートしない Java SE のバージョンとの下位互換性を確保するためです。型消去のために、List<Number>
と List<String>
は List
になります。その結果、コンパイラはオブジェクト l
(List
という raw 型を持つ) をオブジェクト ls
に代入することを許可します。
public class ArrayBuilder { public static <T> void addToList (List<T> listArg, T... elements) { for (T x : elements) { listArg.add(x); } } }コンパイラは、メソッド
ArrayBuilder.addToList
の定義に関する次の警告を生成します。
warning: [varargs] Possible heap pollution from parameterized vararg type Tコンパイラが可変引数メソッド検出すると、可変引数仮パラメータを配列に変換します。しかし、Java プログラミング言語では、パラメータ化された型の配列の作成は許可されません。メソッド
ArrayBuilder.addToList
では、コンパイラは varargs の仮パラメータ T... elements
を仮パラメータ T[] elements
に (配列) 変換します。しかし、型消去のために、コンパイラは varargs の仮パラメータを Object[] elements
に変換します。その結果、ヒープ汚染が発生する可能性があります。
javac のコマンド行を短くしたり簡潔にしたりするために、javac
コマンドに対する引数 (-J
オプションを除く) が入った 1 つ以上のファイルを指定できます。この方法を使うと、どのオペレーティングシステム上でも、任意の長さの javac コマンドを作成できます。
引数ファイルには、javac のオプションとソースファイル名を自由に組み合わせて記述できます。ファイル内の各引数は、スペースまたは改行で区切ります。ファイル名に空白が含まれている場合は、そのファイル名全体を二重引用符で囲みます。
引数ファイル内のファイル名は、現在のディレクトリから見た相対パスになります。引数ファイルの位置から見た相対パスではありません。これらのリストでは、ワイルドカード (*) (*.java
と指定するなど) は使用できません。ファイルを再帰的に解釈するための「@」文字の使用はサポートされていません。-J
オプションもサポートされていません (起動ツールには渡されますが、それが引数ファイルをサポートしていないため)。
javac を実行するときに、各引数ファイルのパスとファイル名の先頭に @ 文字を付けて渡します。javac は、@ 文字で始まる引数を見つけると、そのファイルの内容を展開して引数リストに挿入します。
argfile
という名前の引数ファイルにすべての Javac 引数を格納し、次のように使用できます。
% javac @argfile
この引数ファイルには、次の例で示されている 2 つのファイルの内容を両方とも入れることができます。
たとえば、javac オプション用に 1 ファイル、ソースファイル名用に 1 ファイルというように、2 つの引数ファイルを作成することもできます。なお、このあとのリストでは、行の継続文字を使用していません。
次を含む options
という名前のファイルを作成します。
-d classes -g -sourcepath /java/pubs/ws/1.3/src/share/classes
次を含む classes
という名前のファイルを作成します。
MyClass1.java MyClass2.java MyClass3.java
次のコマンドを使用して javac を実行します。
% javac @options @classes
引数ファイルにパスを指定できますが、ファイル内のファイル名は (path1
や path2
ではなく) 現在の作業ディレクトリへの相対です。
% javac @path1/options @path2/classes
javac が注釈処理を直接サポートしているため、独立した注釈処理ツールである apt を使用する必要がなくなりました。
注釈処理の API は、javax.annotation.processing
および javax.lang.model
パッケージとそのサブパッケージ内に定義されています。
-proc:none オプションによって注釈処理が無効化されないかぎり、コンパイラは使用可能なすべての注釈プロセッサを検索します。検索パスは -processorpath オプションを使って指定できます。検索パスを指定しなかった場合は、ユーザークラスパスが使用されます。プロセッサの検索は、検索パス上の META-INF/services/javax.annotation.processing.Processor
という名前のサービスプロバイダ構成ファイルに基づいて行われます。このようなファイルには、使用するすべての注釈プロセッサの名前を、1 行に 1 つずつ含めてください。また、別の方法として、-processor オプションを使ってプロセッサを明示的に指定することもできます。
コンパイラは、コマンド行のソースファイルやクラスを走査することで、どのような注釈が存在しているかを確認し終わると、プロセッサに対して問い合わせを行い、それらのプロセッサがどの注釈を処理できるのかを確認します。一致するものが見つかった場合、そのプロセッサが呼び出されます。各プロセッサは、自身が処理する注釈を「要求」できます。その場合、それらの注釈に対する別のプロセッサを見つける試みは行われません。すべての注釈が要求されてしまうと、コンパイラはそれ以上プロセッサの検索を行いません。
いずれかのプロセッサによって新しいソースファイルが生成されると、注釈処理の 2 回目のラウンドが開始されます。新しく生成されたすべてのソースファイルが走査され、前回と同様に注釈が処理されます。以前のラウンドで呼び出されたプロセッサはすべて、後続のどのラウンドでも呼び出されます。これが、新しいソースファイルが生成されなくなるまで続きます。
あるラウンドで新しいソースファイルが生成されなかった場合、注釈プロセッサがあと 1 回だけ呼び出され、必要な処理を実行する機会が与えられます。最後に、-proc:only オプションが使用されないかぎり、コンパイラは、元のソースファイルと生成されたすべてのソースファイルをコンパイルします。
コンパイラは、一連のソースファイルをコンパイルする際に、別のソースファイルを暗黙的にロードしなければならない場合があります。(「型の検索」を参照)。そのようなファイルは、現時点では注釈処理の対象になりません。デフォルトでは、注釈処理が実行され、かつ暗黙的にロードされたソースファイルが 1 つでもコンパイルされた場合にコンパイラは警告を発行します。この警告を抑制する方法については、-implicit オプションを参照してください。
ソースファイルをコンパイルする場合、コマンド行で指定したソースファイルに型の定義が見つからないとき、コンパイラは通常、その型に関する情報を必要とします。コンパイラは、ソースファイルで使われているクラスまたはインタフェース、拡張されているクラスまたはインタフェース、あるいは実装されているクラスまたはインタフェースすべてについて、型の情報を必要とします。これには、ソースファイルで明示的には言及されていなくても、継承を通じて情報を提供するクラスとインタフェースも含まれます。
たとえば、java.applet.Applet をサブクラスにした場合、アプレットの祖先のクラス(java.awt.Panel、java.awt.Container、java.awt.Component、java.lang.Object) を使用していることになります。
コンパイラは、型の情報が必要になると、その型を定義しているソースファイルまたはクラスファイルを探します。まず、ブートストラップクラスと拡張機能クラスを検索し、続いてユーザークラスパス (デフォルトではカレントディレクトリ) を検索します。ユーザークラスパスは、CLASSPATH 環境変数を設定して定義するか、または -classpath コマンド行オプションを使って設定します。詳細は、「クラスパスの設定」を参照してください。
-sourcepath オプションが指定されている場合、コンパイラは、指定されたパスからソースファイルを検索します。それ以外の場合は、ユーザークラスパスからクラスファイルとソースファイルの両方を検索します。
-bootclasspath オプションと -extdirs オプションを使うと、別のブートストラップクラスや拡張機能クラスを指定できます。このあとの「クロスコンパイルオプション」を参照してください。
型の検索に成功したときに得られる結果は、クラスファイル、ソースファイル、またはその両方である場合があります。両方が見つかった場合、そのどちらを使用すべきかを -Xprefer オプションでコンパイラに指示できます。newer が指定された場合、コンパイラは 2 つのファイルの新しい方を使用します。source が指定された場合、コンパイラはソースファイルを使用します。デフォルトは newer です。
型の検索自体によって、または -Xprefer が設定された結果として必要な型のソースファイルが見つかった場合、コンパイラはそのソースファイルを読み取り、必要な情報を取得します。さらに、コンパイラはデフォルトで、そのソースファイルのコンパイルも行います。-implicit オプションを使えばその動作を指定できます。none を指定した場合、そのソースファイルのクラスファイルは生成されません。class を指定した場合、そのソースファイルのクラスファイルが生成されます。
コンパイラは、注釈処理の完了後に、ある型情報の必要性を認識しない場合があります。その型情報があるソースファイル内に見つかり、かつ -implicit オプションが指定されていない場合は、そのファイルが注釈処理の対象とならずにコンパイルされることを、コンパイラがユーザーに警告します。この警告を無効にするには、(そのファイルが注釈処理の対象となるように) そのファイルをコマンド行に指定するか、あるいはそのようなソースファイルに対してクラスファイルを生成すべきかどうかを -implicit オプションを使って指定します。
javac は、javax.tools
パッケージ内のクラスとインタフェースによって定義される新しい Java Compiler API をサポートします。
コマンド行から指定された引数を使ってコンパイルを実行するには、次のようなコードを使用します。
JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); int rc = javac.run(null, null, null, args);
この場合、標準出力ストリームにすべての診断メッセージが書き出され、コマンド行から呼び出された javac が返すのと同じ終了コードが返されます。
javax.tools.JavaCompiler
インタフェース上のほかのメソッドを使えば、診断メッセージの処理やファイルの読み取り元/書き込み先の制御などを行えます。
注:この API は、下位互換性を確保するためだけに残されています。新しいコードでは、必ず前述の Java Compiler API を使用してください。
com.sun.tools.javac.Main
クラスには、プログラム内からコンパイラを呼び出すための static メソッドが 2 つ用意されています。それらを次に示します。
public static int compile(String[] args); public static int compile(String[] args, PrintWriter out);
args
パラメータは、javac プログラムに通常渡される任意のコマンド行引数を表しています。その概要については、前出の「形式」セクションを参照してください。
out
パラメータは、コンパイラの診断メッセージの出力先を示します。
戻り値は、javac の終了値と同じです。
名前が com.sun.tools.javac
で始まるパッケージ (非公式には com.sun.tools.javac
のサブパッケージとして知られる) に含まれるその他のクラスやメソッドは、いずれも完全に内部用であり、いつでも変更される可能性があります。
Hello.java
というソースファイルで、greetings.Hello という名前のクラスを定義しているとします。greetings
ディレクトリは、ソースファイルとクラスファイルの両方があるパッケージディレクトリで、現在のディレクトリのすぐ下にあります。このため、この例では、デフォルトのユーザークラスパスを使用できます。また、-d を使って別の出力先ディレクトリを指定する必要もありません。
% ls greetings/ % ls greetings Hello.java % cat greetings/Hello.java package greetings; public class Hello { public static void main(String[] args) { for (int i=0; i < args.length; i++) { System.out.println("Hello " + args[i]); } } } % javac greetings/Hello.java % ls greetings Hello.class Hello.java % java greetings.Hello World Universe Everyone Hello World Hello Universe Hello Everyone
次の例では、パッケージ greetings
内のすべてのソースファイルをコンパイルします。
% ls greetings/ % ls greetings Aloha.java GutenTag.java Hello.java Hi.java % javac greetings/*.java % ls greetings Aloha.class GutenTag.class Hello.class Hi.class Aloha.java GutenTag.java Hello.java Hi.java
上の例のソースファイルのうち 1 つを変更し、変更後のファイルを再コンパイルするとします。
% pwd /examples % javac greetings/Hi.java
greetings.Hi
は、greetings
パッケージ内のほかのクラスを参照しているため、コンパイラはこれらのクラスを探す必要があります。上の例では、デフォルトのユーザークラスパスが、パッケージディレクトリを含むディレクトリと同じであるため、コンパイルは正常に実行されます。ただし、現在どのディレクトリにいるかに関係なく、このファイルを再コンパイルする場合は、ユーザークラスパスに /examples
を追加する必要があります。ユーザークラスパスにエントリを追加するには、CLASSPATH を設定する方法もありますが、ここでは -classpath オプションを使うことにします。
% javac -classpath /examples /examples/greetings/Hi.java
再度 greetings.Hi
を変更してバナーユーティリティーを使うようにした場合は、このバナーユーティリティーもユーザークラスパスを通じてアクセスできるようになっている必要があります。
% javac -classpath /examples:/lib/Banners.jar \ /examples/greetings/Hi.java
greetings
内のクラスを実行するには、greetings
と、greetings が使うクラスの両方にアクセスできる必要があります。
% java -classpath /examples:/lib/Banners.jar greetings.Hi
特に大規模プロジェクトの場合は、ソースファイルとクラスファイルを別々のディレクトリに置くと便利なことがあります。クラスファイルの出力先を別に指定するには、-d を使います。ソースファイルはユーザークラスパスにはないので、-sourcepath を使って、コンパイラがソースファイルを見つけることができるようにします。
% ls classes/ lib/ src/ % ls src farewells/ % ls src/farewells Base.java GoodBye.java % ls lib Banners.jar % ls classes % javac -sourcepath src -classpath classes:lib/Banners.jar \ src/farewells/GoodBye.java -d classes % ls classes farewells/ % ls classes/farewells Base.class GoodBye.class
注:コマンド行では src/farewells/Base.java
を指定していませんが、このファイルもコンパイラによってコンパイルされています。自動コンパイルを監視するには、-verbose オプションを使います。
次の例は、1.6 VM 上で動作するコードをコンパイルするために javac を使用します。
% javac -source 1.6 -target 1.6 -bootclasspath jdk1.6.0/lib/rt.jar \ -extdirs "" OldCode.java
-source 1.6
オプションを指定すると、OldCode.java
のコンパイルにはバージョン 1.6 (または 6) の Java プログラミング言語が使用されます。-target 1.6 オプションを使用すると、1.6 VM と互換性のあるクラスファイルが生成されます。ほとんどの場合、-target オプションの値は -source オプションの値になります。この例では、-target オプションを省略できます。
-bootclasspath オプションを使用して、正しいバージョンのブートストラップクラス (rt.jar
ライブラリ) を指定する必要があります。指定しなかった場合は、コンパイラによって次の警告が生成されます。
% javac -source 1.6 OldCode.java warning: [options] bootstrap class path not set in conjunction with -source 1.6
正しいバージョンのブートストラップクラスを指定しなかった場合、コンパイラは古い言語規則 (この例では、バージョン 1.6 の Java プログラミング言語) を新しいブートストラップクラスと組み合わせて使用します。その結果、存在しないメソッドへの参照が含まれていることがあるため、クラスファイルが古いプラットフォーム (この場合は Java SE 6) で動作しない可能性があります。