日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java compiler类_Java_Java Compiler 应用实例

發布時間:2023/12/8 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java compiler类_Java_Java Compiler 应用实例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://hejiangtao.iteye.com/blog/1399122

一直在用JDK1.5, 一直搞不清楚JDK1.6有啥特性, 就翻了翻, 發現這個Compiler API(JSR 199)動態編譯Java源文件功能很有意思. Compiler API如果和反射功能一起使用, 就可以實現java源代碼的動態編譯并執行這些代碼,有點動態語言的特征. 利用這些API普通用戶也可以方便的開發自己的編譯器,動態生成代碼,編譯并運行. 本文就通過一個動態編譯并運行源文件的例子簡單說明下Compile API的基本功能, 有興趣的可以深入研究下. 本實例的完成工程代碼可以從這里?下載: http://dl.iteye.com/topics/download/0807c557-4f0d-3aba-956f-9fe5c9b83962

實例中實現的功能描述:

1. 使用JavaCompiler對象的run方法編譯java源代碼,并在源代碼所在目錄生成對應的class文件

2. 使用JavaCompiler對象的getTask方法編譯java源代碼,并將對應的class文件生成到指定目錄, 并執行所生成類中指定的"printClassName"方法

環境準備:

首先回顧一下JDK, JRE,JVM的概念和關系:

JRE是java的運行環境, 說白了有JRE才能運行java類; 同時java類是運行于虛擬機(JVM)上的, 其實虛擬機是JRE的一部分, 具體來講,在windows上就是JRE下面的一個JVM.dll文件; JDK就是java開發工具箱, 具有編譯java類的功能和運行java類的功能(自身包含了一個JRE).

知道了JDK,JRE,JVM的關系,我們就應該明白,如果要在eclipse里面使用java的編譯功能必須在eclipse里面使用JDK作為Library,否則在eclipse中獲取不了JavaCompiler的對象. 設置如下圖:

懶得找JDK1.6,我就直接下載了個1.7裝了下,然后開發工具使用MyEclipse (當然用的是免費版的 -:)).

在看我們的實例分析及源碼:

首先看下run方法編譯java源文件, run方法比較簡單,但不能指定輸出路徑,監控錯誤信息, 調用后就在源碼所在目錄生成class文件,run方法的聲明如下:

int?run(InputStream?in,

OutputStream?out,

OutputStream?err,

String...?arguments)使用給定?I/O?通道和參數運行工具。按照慣例,工具如果運行成功,則返回?0;如果出現錯誤,則返回非?0?值。任何生成的診斷都將以某種未指定的格式寫入?out?或?err。

參數:

in?-?“標準”輸入;如果為?null,則使用?System.in

out?-?“標準”輸出;如果為?null,則使用?System.out

err?-?“標準”錯誤;如果為?null,則使用?System.err

arguments?-?要傳遞給工具的參數

返回:

如果成功,則返回?0;否則返回非?0?值

拋出:

NullPointerException?-?如果參數數組包含任何?null?元素。

實例源碼,注釋比較詳細,不再解釋,Compiler.java中代碼片段:

/**

*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com

*?@param?sFullFileName:?the?java?source?file?name?with?full?path

*?@return?bRet:?true-compile?successfully,?false?-?compile?unsuccessfully

*?Description:?Compile?java?source?file?to?java?class?with?run?method

*/

public???boolean??compileFile(String?sFullFileName)

{

boolean??bRet?=??false?;

//?get?compiler

JavaCompiler?oJavaCompiler?=?ToolProvider.getSystemJavaCompiler();

//?compile?the?java?source?code?by?run?method

int??iCompileRet?=?oJavaCompiler.run(?null?,??null?,??null?,?sFullFileName);

//?set?compile?result

if??(?0??==?iCompileRet)

{

bRet?=?true?;

}

return??bRet;

}

再看下我們的getTask方法編譯java源代碼, 這個方法其實是構造了一個JavaCompiler.CompilationTask對象, 然后在調用這個對象的call方法, 在構造對象的過程中, 可以指定class的生成路徑,監控錯誤信息,調用過程如下:

1) 生成JavaCompiler對象,用于構造CompilationTask對象,并編譯java源代碼

2) 構造DiagnosticCollector對象,用于存儲診斷信息

3) 構造oStandardJavaFileManager對象,用于設置類的生成路徑, 為了方便使用java反射方法,我直接將本實例中的輸出路徑設置為工程bin目錄.實際應用中應根據場景生成道不同的目錄--比如可以根據配置或者包名來做.

4) 生成源文件迭代器Iterable對象, 用于存儲java源代碼文件完整的路徑

5) 根據上面生成的對象, 調用JavaCompiler對象的getTask構造CompilationTask對象, 并調用其call方法,編譯源代碼

再看下getTask方法的聲明:

JavaCompiler.CompilationTask?getTask(Writer?out,

JavaFileManager?fileManager,

DiagnosticListener?super?JavaFileObject>?diagnosticListener,

Iterable?options,

Iterable?classes,

Iterable?extends?JavaFileObject>?compilationUnits) 使用給定組件和參數創建編譯任務的?future。該編譯可能沒有完成,正如?CompilationTask?接口中所述。

如果提供了文件管理器,則它必須能夠處理?StandardLocation?中定義的所有位置。

參數:

out?-?用于來自編譯器的其他輸出的?Writer;如果為?null,則使用?System.err

fileManager?-?文件管理器;如果為?null,則使用編譯器的標準文件管理器

diagnosticListener?-?診斷偵聽器;如果為?null,則使用編譯器的默認方法報告診斷信息

options?-?編譯器選項;null?表示沒有選項

classes?-?類名稱(用于注釋處理),null?表示沒有類名稱

compilationUnits?-?要編譯的編譯單元;null?表示沒有編譯單元

返回:

表示編譯的對象

拋出:

RuntimeException?-?如果在用戶提供的組件中發生不可恢復的錯誤。cause?為用戶代碼中的錯誤。

IllegalArgumentException?-?如果給定的任一編譯單元具有不同于?source?的類型

源碼清單如下,Compiler.java中代碼片段:

/**

*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com

*?@param?sFullFileName:?the?java?source?file?name?with?full?path

*?@param?sOutputPath:?the?output?path?of?java?class?file

*?@return?bRet:?true-compile?successfully,?false?-?compile?unsuccessfully

*?Description:?Compile?java?source?file?to?java?class?with?getTask

*?????method,?it?can?specify?the?class?output?path?and?catch?diagnostic

*?????information

*?@throws?IOException

*/

public???boolean??compileFile(String?sFullFileName,?String?sOutputPath)??throws??IOException

{

boolean??bRet?=??false?;

//?get?compiler

JavaCompiler?oJavaCompiler?=?ToolProvider.getSystemJavaCompiler();

//?define?the?diagnostic?object,?which?will?be?used?to?save?the

//?diagnostic?information

DiagnosticCollector?oDiagnosticCollector?=?new??DiagnosticCollector();

//?get?StandardJavaFileManager?object,?and?set?the?diagnostic?for?the

//?object

StandardJavaFileManager?oStandardJavaFileManager?=?oJavaCompiler

.getStandardFileManager(oDiagnosticCollector,?null?,??null?);

//?set?class?output?location

Location?oLocation?=?StandardLocation.CLASS_OUTPUT;

try

{

oStandardJavaFileManager.setLocation(oLocation,?Arrays

.asList(new??File[]?{??new??File(sOutputPath)?}));

//?get?JavaFileObject?object,?it?will?specify?the?java?source?file.

Iterable?extends??JavaFileObject>?oItJavaFileObject?=?oStandardJavaFileManager

.getJavaFileObjectsFromFiles(Arrays.asList(new??File(

sFullFileName)));

//?compile?the?java?source?code?by?using?CompilationTask's?call

//?method

bRet?=?oJavaCompiler.getTask(null?,?oStandardJavaFileManager,

oDiagnosticCollector,?null?,??null?,?oItJavaFileObject).call();

//print?the?Diagnostic's?information

for??(Diagnostic?oDiagnostic?:?oDiagnosticCollector

.getDiagnostics())

{

System.out.println("Error?on?line:?"

+?oDiagnostic.getLineNumber()?+?";?URI:?"

+?oDiagnostic.getSource().toString());

}

}

catch??(IOException?e)

{

//exception?process

System.out.println("IO?Exception:?"??+?e);

throw??e;

}

finally

{

//close?file?manager

if??(?null??!=?oStandardJavaFileManager)

{

oStandardJavaFileManager.close();

}

}

return??bRet;

}

編譯的方法就這兩個簡單吧, 下面我們測試下這兩個方法:

首先, 聲明下我們的compiler類的對象,初始化下編譯的類和輸出類的路徑,MyMain.java中代碼片段:

//?get?compiler?object

Compiler?oCompiler?=?new?Compiler();

//?the?java?source?file?name?with?full?path

String?sFullFileName?=?"E:\\myspace\\CompilerSample\\Sample.java";

//?define?the?output?path?of?java?class,?since?this?demo?is?ran?into

//?eclipse,?so?set?it?as?bin

String?sOutputPath?=?"bin/";

測試run方法:

//?Compile?java?source?file?to?java?class?with?run?method

boolean??bRet?=?oCompiler.compileFile(sFullFileName);

//?print?result

if??(bRet)

{

System.out.println("Compile?the?source?code?\""??+?sFullFileName

+?"\"?successfully"?);

}

else

{

System.out.println("Compile?the?source?code?\""??+?sFullFileName

+?"\"?unsuccessfully"?);

}

run方法測試,控制臺信息:

Compile?the?source?code?"E:\myspace\CompilerSample\Sample.java"?successfully

生成的類文件抓圖:

測試getTask方法,并利用java反射運行所生成類中的"printClassName"方法:

//?Compile?java?source?file,?and?output?the?class?file?into?specified

//?path

bRet?=?oCompiler.compileFile(sFullFileName,?sOutputPath);

//?print?result

if??(bRet)

{

System.out.println("Compile?the?source?code?\""??+?sFullFileName

+?"\"?successfully"?);

//?if?compile?success,?then?execute?the?printClassName?method?of?the

//?compiled?class

System.out

.println("Execute?the?printClassName?method?of?the?compiled?class:?"?);

System.out.print("??"?);

//?load?the?class

Class?oClass?=?Class.forName("Sample"?);

//?new?an?object?of?sample?class

Object?oObject?=?oClass.newInstance();

//?get?object?of?printClassName?method

Method?oMethod?=?oClass.getMethod("printClassName"?);

oMethod.invoke(oObject);

}

else

{

System.out.println("Compile?the?source?code?\""??+?sFullFileName

+?"\"?unsuccessfully"?);

}

}

運行測試方法后,控制臺打印信息:

Compile?the?source?code?"E:\myspace\CompilerSample\Sample.java"?successfully

Execute?the?printClassName?method?of?the?compiled?class:

Print?the?class?name:?Sample

生成的類文件抓圖:

至此, 通過java Compiler API動態編譯并運行源文件的例子就完了.

總結

以上是生活随笔為你收集整理的java compiler类_Java_Java Compiler 应用实例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。