Java千百問_08 JDK詳細(008)_コードによるjavaファイルのコンパイル方法
クリックしてその他Java千百問
1、javaファイルをコードでどのようにコンパイルするか
コンパイラはコマンドラインツール(jdkが持参したコンパイラツールjavac、javacはここを参照:javacとは何か)ですが、APIを使用して呼び出すこともできます(一般的なIDEではこのAPIのセットを使用して独自のコンパイル機能をカプセル化します).コンパイラはJava言語仕様(The Java Language Specification,JLS)とJava仮想マシン仕様に従います(The Java Virtual Machine Specification,JVMS).Java 6の後、Javaコンパイラを操作するための標準パッケージが提供されています.これがjavax.toolsパッケージです.このパッケージのAPIおよびその他の補助パッケージを使用して、独自のコンパイラをカスタマイズできます.ToolProviderクラスのソースコードから、javax.toolsというパッケージのAPIは最終的にtools.jarのcom.sun.tを通じて行われていることがわかります.ools.JAvacパッケージはJavaコンパイラを呼び出します.
コードコンパイルjavaには大体次の3つの方法があり、これらの方法を活用してDIYが自分のコンパイラに属することができます.
JavaCompiler経由run()の最も簡単な使い方はJavaCompilerクラスを用いたrunメソッドで,最初の3つのパラメータはそれぞれ入力情報,出力情報,エラー情報,nullであればデフォルトはSystemである.in、System.out、System.err.最後のパラメータはjavac後のコマンドテキスト、例えばTestに入力.JAvaは、端末でjavac Testを実行することに等しい.java.
例:
実行結果(出力情報が指定されていないため、デフォルトではSystem.outに印刷されます):
javac 1.7.0_79 ===0
JavaCompiler経由getTask()コンパイルハードディスクのコードはJavaCompilerを使用する.run法は非常に簡単であるが,我々が必要とする情報をより効果的に得ることはできない.一般的にStandardJavaFileManagerクラス(jdk 6以上)を使用します.このクラスは入力、出力をよく制御し、DiagnosticListenerで診断情報を得ることができます.DiagnosticCollectorクラスはlistener(リスニング)の実装です.
具体的な例は次のとおりです.
実行結果は次のとおりです.
コンパイル成功
対応する経路でcom/test/Testが発見される.classファイル(Testのパッケージはpackage com.testなので、対応するディレクトリの下で自動的にcom/test/パスが生成されます).
JavaCompilerでgetTask()コンパイルメモリ内のコードJavaCompilerは、ハードディスク上のJavaファイルだけでなく、メモリ内のJavaコードをコンパイルしてreflectionを使用して実行することもできます.JavaSourceFromStringクラスを作成できます.このクラスでJavaソースコードを入力できます.
具体的な例は次のとおりです.
実行結果は次のとおりです.
コンパイル成功
対応するパスの下にハローワールドがあります.classファイル.
1、javaファイルをコードでどのようにコンパイルするか
コンパイラはコマンドラインツール(jdkが持参したコンパイラツールjavac、javacはここを参照:javacとは何か)ですが、APIを使用して呼び出すこともできます(一般的なIDEではこのAPIのセットを使用して独自のコンパイル機能をカプセル化します).コンパイラはJava言語仕様(The Java Language Specification,JLS)とJava仮想マシン仕様に従います(The Java Virtual Machine Specification,JVMS).Java 6の後、Javaコンパイラを操作するための標準パッケージが提供されています.これがjavax.toolsパッケージです.このパッケージのAPIおよびその他の補助パッケージを使用して、独自のコンパイラをカスタマイズできます.ToolProviderクラスのソースコードから、javax.toolsというパッケージのAPIは最終的にtools.jarのcom.sun.tを通じて行われていることがわかります.ools.JAvacパッケージはJavaコンパイラを呼び出します.
コードコンパイルjavaには大体次の3つの方法があり、これらの方法を活用してDIYが自分のコンパイラに属することができます.
JavaCompiler経由run()の最も簡単な使い方はJavaCompilerクラスを用いたrunメソッドで,最初の3つのパラメータはそれぞれ入力情報,出力情報,エラー情報,nullであればデフォルトはSystemである.in、System.out、System.err.最後のパラメータはjavac後のコマンドテキスト、例えばTestに入力.JAvaは、端末でjavac Testを実行することに等しい.java.
例:
public class Test {
public static void main(String[] args) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int run = compiler.run(null, null, null, "-version");
System.out.println("===" + run);
}
}
実行結果(出力情報が指定されていないため、デフォルトではSystem.outに印刷されます):
javac 1.7.0_79 ===0
JavaCompiler経由getTask()コンパイルハードディスクのコードはJavaCompilerを使用する.run法は非常に簡単であるが,我々が必要とする情報をより効果的に得ることはできない.一般的にStandardJavaFileManagerクラス(jdk 6以上)を使用します.このクラスは入力、出力をよく制御し、DiagnosticListenerで診断情報を得ることができます.DiagnosticCollectorクラスはlistener(リスニング)の実装です.
具体的な例は次のとおりです.
public class Test {
public static void main(String[] args) throws Exception {
Test.compiler();
}
public static void compiler() throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// DiagnosticCollector
DiagnosticCollector diagnostics = new DiagnosticCollector();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// , JavaFileObject
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Arrays
.asList("/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/Test.java"));
// options
Iterable<String> options = Arrays.asList("-d",
"/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// ,javac
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null,
compilationUnits);
//
boolean success = task.call();
fileManager.close();
System.out.println((success) ? " " : " ");
//
for (Object object : diagnostics.getDiagnostics()) {
Diagnostic diagnostic = (Diagnostic) object;
System.out.printf("Code: %s%n" + "Kind: %s%n" + "Position: %s%n" + "Start Position: %s%n"
+ "End Position: %s%n" + "Source: %s%n" + "Message: %s%n", diagnostic.getCode(),
diagnostic.getKind(), diagnostic.getPosition(), diagnostic.getStartPosition(),
diagnostic.getEndPosition(), diagnostic.getSource(), diagnostic.getMessage(null));
}
}
}
実行結果は次のとおりです.
コンパイル成功
対応する経路でcom/test/Testが発見される.classファイル(Testのパッケージはpackage com.testなので、対応するディレクトリの下で自動的にcom/test/パスが生成されます).
JavaCompilerでgetTask()コンパイルメモリ内のコードJavaCompilerは、ハードディスク上のJavaファイルだけでなく、メモリ内のJavaコードをコンパイルしてreflectionを使用して実行することもできます.JavaSourceFromStringクラスを作成できます.このクラスでJavaソースコードを入力できます.
具体的な例は次のとおりです.
public class Test {
public static void main(String[] args) throws Exception {
Test.compiler2();
}
public static void compiler2() throws IOException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector diagnostics = new DiagnosticCollector();
// StringWriter , Java
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
// Java
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.println(\"Hello, World\");");
out.println(" }");
out.println("}");
out.close();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
// :HelloWorld
SimpleJavaFileObject file = (new Test()).new JavaSourceFromString("HelloWorld", writer.toString());
Iterable compilationUnits = Arrays.asList(file);
// options
Iterable<String> options = Arrays.asList("-d",
"/Users/sunjie/Desktop/works/workspace/my-test/src/com/test/classes");// ,javac
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null,
compilationUnits);
boolean success = task.call();
System.out.println((success) ? " " : " ");
}
// JavaSourceFromString
class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
}
実行結果は次のとおりです.
コンパイル成功
対応するパスの下にハローワールドがあります.classファイル.