欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Java SE 6 新特性: 編譯器 API

2006 年底,Sun 公司發(fā)布了 Java Standard Edition 6(Java SE 6)的最終正式版,代號 Mustang(野馬)。跟 Tiger(Java SE 5)相比,Mustang 在性能方面有了不錯的提升。與 Tiger 在 API 庫方面的大幅度加強相比,雖然 Mustang 在 API 庫方面的新特性顯得不太多,但是也提供了許多實(shí)用和方便的功能:在腳本,WebService,XML,編譯器 API,數據庫,JMX,網(wǎng)絡(luò )和 Instrumentation 方面都有不錯的新特性和功能加強。 本系列 文章主要介紹 Java SE 6 在 API 庫方面的部分新特性,通過(guò)一些例子和講解,幫助開(kāi)發(fā)者在編程實(shí)踐當中更好的運用 Java SE 6,提高開(kāi)發(fā)效率。

本文是其中的第四篇,介紹了 JDK 6 中為在運行時(shí)操縱編譯器所增加的編譯器 API(JSR 199)。您將了解到,利用此 API 開(kāi)發(fā)人員可以在運行時(shí)調用 Java 編譯器,還可以編譯非文本形式的 Java 源代碼,最后還能夠采集編譯器的診斷信息。本文將展開(kāi)描述這些功能,并使用這些功能構造一個(gè)簡(jiǎn)單的應用 —— 在內存中,直接為一個(gè)類(lèi)生成測試用例。

新 API 功能簡(jiǎn)介

JDK 6 提供了在運行時(shí)調用編譯器的 API,后面我們將假設把此 API 應用在 JSP 技術(shù)中。在傳統的 JSP 技術(shù)中,服務(wù)器處理 JSP 通常需要進(jìn)行下面 6 個(gè)步驟:

  1. 分析 JSP 代碼;
  2. 生成 Java 代碼;
  3. 將 Java 代碼寫(xiě)入存儲器;
  4. 啟動(dòng)另外一個(gè)進(jìn)程并運行編譯器編譯 Java 代碼;
  5. 將類(lèi)文件寫(xiě)入存儲器;
  6. 服務(wù)器讀入類(lèi)文件并運行;

但如果采用運行時(shí)編譯,可以同時(shí)簡(jiǎn)化步驟 4 和 5,節約新進(jìn)程的開(kāi)銷(xiāo)和寫(xiě)入存儲器的輸出開(kāi)銷(xiāo),提高系統效率。實(shí)際上,在 JDK 5 中,Sun 也提供了調用編譯器的編程接口。然而不同的是,老版本的編程接口并不是標準 API 的一部分,而是作為 Sun 的專(zhuān)有實(shí)現提供的,而新版則帶來(lái)了標準化的優(yōu)點(diǎn)。

新 API 的第二個(gè)新特性是可以編譯抽象文件,理論上是任何形式的對象 —— 只要該對象實(shí)現了特定的接口。有了這個(gè)特性,上述例子中的步驟 3 也可以省略。整個(gè) JSP 的編譯運行在一個(gè)進(jìn)程中完成,同時(shí)消除額外的輸入輸出操作。

第三個(gè)新特性是可以收集編譯時(shí)的診斷信息。作為對前兩個(gè)新特性的補充,它可以使開(kāi)發(fā)人員輕松的輸出必要的編譯錯誤或者是警告信息,從而省去了很多重定向的麻煩。





回頁(yè)首


運行時(shí)編譯 Java 文件

在 JDK 6 中,類(lèi)庫通過(guò) javax.tools 包提供了程序運行時(shí)調用編譯器的 API。從這個(gè)包的名字 tools 可以看出,這個(gè)開(kāi)發(fā)包提供的功能并不僅僅限于編譯器。工具還包括 javah、jar、pack200 等,它們都是 JDK 提供的命令行工具。這個(gè)開(kāi)發(fā)包希望通過(guò)實(shí)現一個(gè)統一的接口,可以在運行時(shí)調用這些工具。在 JDK 6 中,編譯器被給予了特別的重視。針對編譯器,JDK 設計了兩個(gè)接口,分別是 JavaCompilerJavaCompiler.CompilationTask。

下面給出一個(gè)例子,展示如何在運行時(shí)調用編譯器。

  • 指定編譯文件名稱(chēng)(該文件必須在 CLASSPATH 中可以找到):String fullQuanlifiedFileName = "compile" + java.io.File.separator +"Target.java";
  • 獲得編譯器對象: JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

通過(guò)調用 ToolProvidergetSystemJavaCompiler 方法,JDK 提供了將當前平臺的編譯器映射到內存中的一個(gè)對象。這樣使用者可以在運行時(shí)操縱編譯器。JavaCompiler 是一個(gè)接口,它繼承了 javax.tools.Tool 接口。因此,第三方實(shí)現的編譯器,只要符合規范就能通過(guò)統一的接口調用。同時(shí),tools 開(kāi)發(fā)包希望對所有的工具提供統一的運行時(shí)調用接口。相信將來(lái),ToolProvider 類(lèi)將會(huì )為更多地工具提供 getSystemXXXTool 方法。tools 開(kāi)發(fā)包實(shí)際為多種不同工具、不同實(shí)現的共存提供了框架。

  • 編譯文件:int result = compiler.run(null, null, null, fileToCompile);

獲得編譯器對象之后,可以調用 Tool.run 方法對源文件進(jìn)行編譯。Run 方法的前三個(gè)參數,分別可以用來(lái)重定向標準輸入、標準輸出和標準錯誤輸出,null 值表示使用默認值。清單 1 給出了一個(gè)完整的例子:


清單 1. 程序運行時(shí)編譯文件
01 package compile;                        02 import java.util.Date;                        03 public class Target {                        04   public void doSomething(){                        05     Date date = new Date(10, 3, 3);                        // 這個(gè)構造函數被標記為deprecated, 編譯時(shí)會(huì )                        // 向錯誤輸出輸出信息。                        06     System.out.println("Doing...");                        07   }                        08 }                        09 package compile;                        10 import javax.tools.*;                        11 import java.io.FileOutputStream;                        12 public class Compiler {                        13   public static void main(String[] args) throws Exception{                        14     String fullQuanlifiedFileName = "compile" + java.io.File.separator +                        "Target.java";                        15     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();                        16     FileOutputStream err = new FileOutputStream("err.txt");                        17     int compilationResult = compiler.run(null, null, err, fullQuanlifiedFileName);                        18     if(compilationResult == 0){                        19       System.out.println("Done");                        20     } else {                        21       System.out.println("Fail");                        22     }                        23   }                        24 }                        

首先運行 <JDK60_INSTALLATION_DIR>\bin\javac Compiler.java,然后運行 <JDK60_INSTALLATION_DIR>\jdk1.6.0\bin\java compile.Compiler。屏幕上將輸出 Done ,并會(huì )在當前目錄生成一個(gè) err.txt 文件,文件內容如下:

Note: compile/Target.java uses or overrides a deprecated API.                        Note: Recompile with -Xlint:deprecation for details.                        

仔細觀(guān)察 run 方法,可以發(fā)現最后一個(gè)參數是 String...arguments,是一個(gè)變長(cháng)的字符串數組。它的實(shí)際作用是接受傳遞給 javac 的參數。假設要編譯 Target.java 文件,并顯示編譯過(guò)程中的詳細信息。命令行為:javac Target.java -verbose。相應的可以將 17 句改為:

int compilationResult = compiler.run(null, null, err, “-verbose”,fullQuanlifiedFileName);                        





回頁(yè)首


編譯非文本形式的文件

JDK 6 的編譯器 API 的另外一個(gè)強大之處在于,它可以編譯的源文件的形式并不局限于文本文件。JavaCompiler 類(lèi)依靠文件管理服務(wù)可以編譯多種形式的源文件。比如直接由內存中的字符串構造的文件,或者是從數據庫中取出的文件。這種服務(wù)是由 JavaFileManager 類(lèi)提供的。通常的編譯過(guò)程分為以下幾個(gè)步驟:

  1. 解析 javac 的參數;
  2. 在 source path 和/或 CLASSPATH 中查找源文件或者 jar 包;
  3. 處理輸入,輸出文件;

在這個(gè)過(guò)程中,JavaFileManager 類(lèi)可以起到創(chuàng )建輸出文件,讀入并緩存輸出文件的作用。由于它可以讀入并緩存輸入文件,這就使得讀入各種形式的輸入文件成為可能。JDK 提供的命令行工具,處理機制也大致相似,在未來(lái)的版本中,其它的工具處理各種形式的源文件也成為可能。為此,新的 JDK 定義了 javax.tools.FileObjectjavax.tools.JavaFileObject 接口。任何類(lèi),只要實(shí)現了這個(gè)接口,就可以被 JavaFileManager 識別。

如果要使用 JavaFileManager,就必須構造 CompilationTask。JDK 6 提供了 JavaCompiler.CompilationTask 類(lèi)來(lái)封裝一個(gè)編譯操作。這個(gè)類(lèi)可以通過(guò):

JavaCompiler.getTask (                        Writer out,                        JavaFileManager fileManager,                        DiagnosticListener<? super JavaFileObject> diagnosticListener,                        Iterable<String> options,                        Iterable<String> classes,                        Iterable<? extends JavaFileObject> compilationUnits                        )                        

方法得到。關(guān)于每個(gè)參數的含義,請參見(jiàn) JDK 文檔。傳遞不同的參數,會(huì )得到不同的 CompilationTask。通過(guò)構造這個(gè)類(lèi),一個(gè)編譯過(guò)程可以被分成多步。進(jìn)一步,CompilationTask 提供了 setProcessors(Iterable<? extends Processor>processors) 方法,用戶(hù)可以制定處理 annotation 的處理器。圖 1 展示了通過(guò) CompilationTask 進(jìn)行編譯的過(guò)程:


圖 1. 使用 CompilationTask 進(jìn)行編譯

下面的例子通過(guò)構造 CompilationTask 分多步編譯一組 Java 源文件。


清單 2. 構造 CompilationTask 進(jìn)行編譯
01 package math;                        02 public class Calculator {                        03     public int multiply(int multiplicand, int multiplier) {                        04         return multiplicand * multiplier;                        05     }                        06 }                        07 package compile;                        08 import javax.tools.*;                        09 import java.io.FileOutputStream;                        10 import java.util.Arrays;                        11 public class Compiler {                        12   public static void main(String[] args) throws Exception{                        13     String fullQuanlifiedFileName = "math" + java.io.File.separator +"Calculator.java";                        14     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();                        15     StandardJavaFileManager fileManager  =                        compiler.getStandardFileManager(null, null, null);                        16     Iterable<? extends JavaFileObject> files =                        fileManager.getJavaFileObjectsFromStrings(                        Arrays.asList(fullQuanlifiedFileName));                        17     JavaCompiler.CompilationTask task = compiler.getTask(                        null, fileManager, null, null, null, files);                        18     Boolean result = task.call();                        19     if( result == true ) {                        20       System.out.println("Succeeded");                        21     }                        22   }                        23 }                        

以上是第一步,通過(guò)構造一個(gè) CompilationTask 編譯了一個(gè) Java 文件。14-17 行實(shí)現了主要邏輯。第 14 行,首先取得一個(gè)編譯器對象。由于僅僅需要編譯普通文件,因此第 15 行中通過(guò)編譯器對象取得了一個(gè)標準文件管理器。16 行,將需要編譯的文件構造成了一個(gè) Iterable 對象。最后將文件管理器和 Iterable 對象傳遞給 JavaCompilergetTask 方法,取得了 JavaCompiler.CompilationTask 對象。

接下來(lái)第二步,開(kāi)發(fā)者希望生成 Calculator 的一個(gè)測試類(lèi),而不是手工編寫(xiě)。使用 compiler API,可以將內存中的一段字符串,編譯成一個(gè) CLASS 文件。


清單 3. 定制 JavaFileObject 對象
01 package math;                        02 import java.net.URI;                        03 public class StringObject extends SimpleJavaFileObject{                        04     private String contents = null;                        05     public StringObject(String className, String contents) throws Exception{                        06         super(new URI(className), Kind.SOURCE);                        07         this.contents = contents;                        08     }                        09     public CharSequence getCharContent(boolean ignoreEncodingErrors)                        throws IOException {                        10         return contents;                        11     }                        12 }                        

SimpleJavaFileObjectJavaFileObject 的子類(lèi),它提供了默認的實(shí)現。繼承 SimpleJavaObject 之后,只需要實(shí)現 getCharContent 方法。如 清單 3 中的 9-11 行所示。接下來(lái),在內存中構造 Calculator 的測試類(lèi) CalculatorTest,并將代表該類(lèi)的字符串放置到 StringObject 中,傳遞給 JavaCompilergetTask 方法。清單 4 展現了這些步驟。


清單 4. 編譯非文本形式的源文件
01 package math;                        02 import javax.tools.*;                        03 import java.io.FileOutputStream;                        04 import java.util.Arrays;                        05 public class AdvancedCompiler {                        06   public static void main(String[] args) throws Exception{                        07     // Steps used to compile Calculator                        08     // Steps used to compile StringObject                        09     // construct CalculatorTest in memory                        10     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();                        11     StandardJavaFileManager fileManager  =                        compiler.getStandardFileManager(null, null, null);                        12         JavaFileObject file = constructTestor();                        13         Iterable<? extends JavaFileObject> files = Arrays.asList(file);                        14         JavaCompiler.CompilationTask task = compiler.getTask (                        null, fileManager, null, null, null, files);                        15         Boolean result = task.call();                        16         if( result == true ) {                        17           System.out.println("Succeeded");                        18         }                        19   }                        20   private static SimpleJavaFileObject constructTestor() {                        21     StringBuilder contents = new StringBuilder(                        "package math;" +                        "class CalculatorTest {\n" +                        "  public void testMultiply() {\n" +                        "    Calculator c = new Calculator();\n" +                        "    System.out.println(c.multiply(2, 4));\n" +                        "  }\n" +                        "  public static void main(String[] args) {\n" +                        "    CalculatorTest ct = new CalculatorTest();\n" +                        "    ct.testMultiply();\n" +                        "  }\n" +                        "}\n");                        22      StringObject so = null;                        23      try {                        24        so = new StringObject("math.CalculatorTest", contents.toString());                        25      } catch(Exception exception) {                        26        exception.printStackTrace();                        27      }                        28      return so;                        29    }                        30 }                        

實(shí)現邏輯和 清單 2 相似。不同的是在 20-30 行,程序在內存中構造了 CalculatorTest 類(lèi),并且通過(guò) StringObject 的構造函數,將內存中的字符串,轉換成了 JavaFileObject 對象。





回頁(yè)首


采集編譯器的診斷信息

第三個(gè)新增加的功能,是收集編譯過(guò)程中的診斷信息。診斷信息,通常指錯誤、警告或是編譯過(guò)程中的詳盡輸出。JDK 6 通過(guò) Listener 機制,獲取這些信息。如果要注冊一個(gè) DiagnosticListener,必須使用 CompilationTask 來(lái)進(jìn)行編譯,因為 Tool 的 run 方法沒(méi)有辦法注冊 Listener。步驟很簡(jiǎn)單,先構造一個(gè) Listener,然后傳遞給 JavaFileManager 的構造函數。清單 5清單 2 進(jìn)行了改動(dòng),展示了如何注冊一個(gè) DiagnosticListener。


清單 5. 注冊一個(gè) DiagnosticListener 收集編譯信息
01 package math;                        02 public class Calculator {                        03   public int multiply(int multiplicand, int multiplier) {                        04     return multiplicand * multiplier                        // deliberately omit semicolon, ADiagnosticListener                        // will take effect                        05   }                        06 }                        07 package compile;                        08 import javax.tools.*;                        09 import java.io.FileOutputStream;                        10 import java.util.Arrays;                        11 public class CompilerWithListener {                        12   public static void main(String[] args) throws Exception{                        13     String fullQuanlifiedFileName = "math" +                        java.io.File.separator +"Calculator.java";                        14     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();                        15     StandardJavaFileManager fileManager  =                        compiler.getStandardFileManager(null, null, null);                        16     Iterable<? extends JavaFileObject> files =                        fileManager.getJavaFileObjectsFromStrings(                        Arrays.asList(fullQuanlifiedFileName));                        17	   DiagnosticCollector<JavaFileObject> collector =                        new DiagnosticCollector<JavaFileObject>();                        18	   JavaCompiler.CompilationTask task =                        compiler.getTask(null, fileManager, collector, null, null, files);                        19     Boolean result = task.call();                        20     List<Diagnostic<? extends JavaFileObject>> diagnostics =                        collector.getDiagnostics();                        21     for(Diagnostic<? extends JavaFileObject> d : diagnostics){                        22         System.out.println("Line Number->" + d.getLineNumber());                        23		   System.out.println("Message->"+                        d.getMessage(Locale.ENGLISH));                        24		   System.out.println("Source" + d.getCode());                        25		   System.out.println("\n");                        26     }                        27     if( result == true ) {                        28       System.out.println("Succeeded");                        29     }                        30   }                        31 }                        

在 17 行,構造了一個(gè) DiagnosticCollector 對象,這個(gè)對象由 JDK 提供,它實(shí)現了 DiagnosticListener 接口。18 行將它注冊到 CompilationTask 中去。一個(gè)編譯過(guò)程可能有多個(gè)診斷信息。每一個(gè)診斷信息,被抽象為一個(gè) Diagnostic。20-26 行,將所有的診斷信息逐個(gè)輸出。編譯并運行 Compiler,得到以下輸出:


清單 6. DiagnosticCollector 收集的編譯信息
Line Number->5                        Message->math/Calculator.java:5: ‘;‘ expected                        Source->compiler.err.expected                        

實(shí)際上,也可以由用戶(hù)自己定制。清單 7 給出了一個(gè)定制的 Listener。


清單 7. 自定義的 DiagnosticListener
01 class ADiagnosticListener implements DiagnosticListener<JavaFileObject>{                        02 	 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {                        03	   System.out.println("Line Number->" + diagnostic.getLineNumber());                        04	   System.out.println("Message->"+ diagnostic.getMessage(Locale.ENGLISH));                        05	   System.out.println("Source" + diagnostic.getCode());                        06	   System.out.println("\n");                        07	 }                        08 }                        





回頁(yè)首


總結

JDK 6 的編譯器新特性,使得開(kāi)發(fā)者可以更自如的控制編譯的過(guò)程,這給了工具開(kāi)發(fā)者更加靈活的自由度。通過(guò) API 的調用完成編譯操作的特性,使得開(kāi)發(fā)者可以更方便、高效地將編譯變?yōu)檐浖到y運行時(shí)的服務(wù)。而編譯更廣泛形式的源代碼,則為整合更多的數據源及功能提供了強大的支持。相信隨著(zhù) JDK 的不斷完善,更多的工具將具有 API 支持,我們拭目以待。



參考資料

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
調用Java編譯器API編譯Java-docman.cn 翻譯家 -JavaEye技術(shù)社區
Java SE6調用Java編譯器的兩種新方法
動(dòng)態(tài)的Java JavaCompilerAPI中文指南
Java版的實(shí)現JavaScript中的eval()函數
【Maven冷知識】Compiler插件
JDK6的新特性之四:使用Compiler API
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久