hk2000c技術(shù)專欄

          技術(shù)源于哲學(xué),哲學(xué)來(lái)源于生活 關(guān)心生活,關(guān)注健康,關(guān)心他人

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            111 隨筆 :: 1 文章 :: 28 評(píng)論 :: 0 Trackbacks

          如果您一直在閱讀這個(gè)系列,那么您應(yīng)該已經(jīng)看到有各種各樣使用 Groovy 的有趣方式,Groovy 的主要優(yōu)勢(shì)之一就是它的生產(chǎn)力。Groovy 代碼通常要比 Java 代碼更容易編寫(xiě),而且編寫(xiě)起來(lái)也更快,這使得它有足夠的資格成為開(kāi)發(fā)工作包中的一個(gè)附件。在另一方面,正如我在這個(gè)系列中反復(fù)強(qiáng)調(diào)的那樣,Groovy 并不是 —— 而且也不打算成為 —— Java 語(yǔ)言的替代。所以,這里存在的問(wèn)題是,能否把 Groovy 集成到 Java 的編程實(shí)踐中?或者說(shuō)這樣做有什么用?什么時(shí)候 這樣做有用?

          這個(gè)月,我將嘗試回答這個(gè)問(wèn)題。我將從一些熟悉的事物開(kāi)始,即從如何將 Groovy 腳本編譯成與 Java 兼容的類文件開(kāi)始,然后進(jìn)一步仔細(xì)研究 Groovy 的編譯工具(groovyc)是如何讓這個(gè)奇跡實(shí)現(xiàn)的。了解 Groovy 在幕后做了什么是在 Java 代碼中使用 Groovy 的第一步。

          注意,本月示例中演示的一些編程技術(shù)是 Groovlets 框架和 Groovy 的 GroovyTestCase 的核心,這些技術(shù)我在前面的文章中已經(jīng)討論過(guò)。

          關(guān)于本系列

          把任何工具集成到自己的開(kāi)發(fā)實(shí)踐的關(guān)鍵就是知道什么時(shí)候使用它,而什么時(shí)候應(yīng)當(dāng)把它留在箱子里。腳本語(yǔ)言能夠成為工具箱中極為強(qiáng)大的附件,但只在將它恰當(dāng)應(yīng)用到合適場(chǎng)景時(shí)才這樣。為此, 實(shí)戰(zhàn) Groovy 的一系列文章專門(mén)探索了 Groovy 的實(shí)際應(yīng)用,并告訴您什么時(shí)候應(yīng)用它們,以及如何成功地應(yīng)用它們。

          天作之合?

          在本系列中以前的文章中,當(dāng)我介紹如何 用 Groovy 測(cè)試普通 Java 程序 的時(shí)候,您可能已經(jīng)注意到一些奇怪的事:我 編譯了 那些 Groovy 腳本。實(shí)際上,我將 groovy 單元測(cè)試編譯成普通的 Java .class 文件,然后把它們作為 Maven 構(gòu)建的一部分來(lái)運(yùn)行。

          這種編譯是通過(guò)調(diào)用 groovyc 命令進(jìn)行的,該命令將 Groovy 腳本編譯成普通的 Java 兼容的 .class 文件。例如,如果腳本聲明了一個(gè)類,那么調(diào)用 groovyc 會(huì)生成至少三個(gè) .class 。文件本身會(huì)遵守標(biāo)準(zhǔn)的 Java 規(guī)則:.class 文件名稱要和聲明的類名匹配。

          作為示例,請(qǐng)參見(jiàn)清單 1,它創(chuàng)建了一個(gè)簡(jiǎn)單的腳本,腳本聲明了幾個(gè)類。然后,您自己就可以看出 groovyc 命令生成的結(jié)果:


          清單 1. Groovy 中的類聲明和編譯
          package com.vanward.groovy class Person {   fname   lname   age   address   contactNumbers   String toString(){         numstr = new StringBuffer()     if (contactNumbers != null){      contactNumbers.each{        numstr.append(it)        numstr.append(" ")      }     }     "first name: " + fname + " last name: " + lname +      " age: " + age + " address: " + address +      " contact numbers: " + numstr.toString()   } } class Address {   street1   street2   city   state   zip   String toString(){    "street1: " + street1 + " street2: " + street2 +      " city: " + city + " state: " + state + " zip: " + zip   } } class ContactNumber {   type   number   String toString(){    "Type: " + type + " number: " + number    } } nums = [new ContactNumber(type:"cell", number:"555.555.9999"),  	new ContactNumber(type:"office", number:"555.555.5598")] addr = new Address(street1:"89 Main St.", street2:"Apt #2",  	city:"Utopia", state:"VA", zip:"34254") pers = new Person(fname:"Mollie", lname:"Smith", age:34,  	address:addr, contactNumbers:nums) println pers.toString() 

          在清單 1 中,我聲明了三個(gè)類 —— PersonAddress 和 ContactNumber。之后的代碼根據(jù)這些新定義的類型創(chuàng)建對(duì)象,然后調(diào)用toString() 方法。迄今為止,Groovy 中的代碼還非常簡(jiǎn)單,但現(xiàn)在來(lái)看一下清單 2 中 groovyc 產(chǎn)生什么樣的結(jié)果:


          清單 2. groovyc 命令生成的類
          aglover@12d21 /cygdrive/c/dev/project/target/classes/com/vanward/groovy $ ls -ls   total 15  4 -rwxrwxrwx+ 1 aglover  user   3317 May  3 21:12 Address.class  3 -rwxrwxrwx+ 1 aglover  user   3061 May  3 21:12 BusinessObjects.class  3 -rwxrwxrwx+ 1 aglover  user   2815 May  3 21:12 ContactNumber.class  1 -rwxrwxrwx+ 1 aglover  user   1003 May  3 21:12     Person$_toString_closure1.class  4 -rwxrwxrwx+ 1 aglover  user   4055 May  3 21:12 Person.class 

          哇!五個(gè) .class 文件!我們了解 PersonAddress 和 ContactNumber 文件的意義,但是其他兩個(gè)文件有什么作用呢?

          研究發(fā)現(xiàn),Person$_toString_closure1.class 是 Person 類的 toString() 方法中發(fā)現(xiàn)的閉包的結(jié)果。它是 Person 的一個(gè)內(nèi)部類,但是 BusinessObjects.class 文件是怎么回事 —— 它可能是什么呢?

          對(duì) 清單 1 的深入觀察指出:我在腳本主體中編寫(xiě)的代碼(聲明完三個(gè)類之后的代碼)變成一個(gè) .class 文件,它的名稱采用的是腳本名稱。在這個(gè)例子中,腳本被命名為 BusinessObjects.groovy,所以,類定義中沒(méi)有包含的代碼被編譯到一個(gè)名為 BusinessObjects的 .class 文件。

          反編譯

          反編譯這些類可能會(huì)非常有趣。由于 Groovy 處于代碼頂層,所以生成的 .java 文件可能相當(dāng)巨大;不過(guò),您應(yīng)當(dāng)注意的是 Groovy 腳本中聲明的類(如 Person) 與類之外的代碼(比如 BusinessObjects.class 中找到的代碼)之間的區(qū)別。在 Groovy 文件中定義的類完成了 GroovyObject 的實(shí)現(xiàn),而在類之外定義的代碼則被綁定到一個(gè)擴(kuò)展自 Script 的類。

          例如,如果研究由 BusinessObjects.class 生成的 .java 文件,可以發(fā)現(xiàn):它定義了一個(gè) main() 方法和一個(gè) run() 方法。不用驚訝,run() 方法包含我編寫(xiě)的、用來(lái)創(chuàng)建這些對(duì)象的新實(shí)例的代碼,而 main() 方法則調(diào)用 run() 方法。

          這個(gè)細(xì)節(jié)的全部要點(diǎn)再一次回到了:對(duì) Groovy 的理解越好,就越容易把它集成到 Java 程序中。有人也許會(huì)問(wèn):“為什么我要這么做呢?”好了,我們想說(shuō)您用 Groovy 開(kāi)發(fā)了一些很酷的東西;那么如果能把這些東西集成到 Java 程序中,那不是很好嗎?

          只是為了討論的原因,我首先試圖 用 Groovy 創(chuàng)建一些有用的東西,然后我再介紹把它嵌入到普通 Java 程序中的各種方法。

          回頁(yè)首

          再制作一個(gè)音樂(lè) Groovy

          我熱愛(ài)音樂(lè)。實(shí)際上,我的 CD 收藏超過(guò)了我計(jì)算機(jī)圖書(shū)的收藏。多年以來(lái),我把我的音樂(lè)截取到不同的計(jì)算機(jī)上,在這個(gè)過(guò)程中,我的 MP3 收藏亂到了這樣一種層度:只是表示品種豐富的音樂(lè)目錄就有一大堆。

          最近,為了讓我的音樂(lè)收藏回歸有序,我采取了第一步行動(dòng)。我編寫(xiě)了一個(gè)快速的 Groovy 腳本,在某個(gè)目錄的 MP3 收藏上進(jìn)行迭代,然后把每個(gè)文件的詳細(xì)信息(例如藝術(shù)家、專輯名稱等)提供給我。腳本如清單 3 所示:


          清單 3. 一個(gè)非常有用的 Groovy 腳本
          package com.vanward.groovy import org.farng.mp3.MP3File import groovy.util.AntBuilder class Song {      mp3file   Song(String mp3name){        mp3file = new MP3File(mp3name)      }   getTitle(){     mp3file.getID3v1Tag().getTitle()   }   getAlbum(){     mp3file.getID3v1Tag().getAlbum()   }   getArtist(){     mp3file.getID3v1Tag().getArtist()   }   String toString(){     "Artist: " + getArtist() + " Album: " +        getAlbum() + " Song: " + getTitle()   }   static getSongsForDirectory(sdir){     println "sdir is: " + sdir     ant = new AntBuilder()     scanner = ant.fileScanner {        fileset(dir:sdir) {          include(name:"**/*.mp3")        }     }     songs = []     for(f in scanner){          songs << new Song(f.getAbsolutePath())        }     return songs   } } songs = Song.getSongsForDirectory(args[0]) songs.each{  println it } 

          正如您所看到的,腳本非常簡(jiǎn)單,對(duì)于像我這樣的人來(lái)說(shuō)特別有用。而我要做的全部工作只是把某個(gè)具體的目錄名傳遞給它,然后我就會(huì)得到該目錄中每個(gè) MP3 文件的相關(guān)信息(藝術(shù)家名稱、歌曲名稱和專輯) 。

          現(xiàn)在讓我們來(lái)看看,如果要把這個(gè)干凈的腳本集成到一個(gè)能夠通過(guò)數(shù)據(jù)庫(kù)組織音樂(lè)甚至播放 MP3 的普通 Java 程序中,我需要做些什么。

          回頁(yè)首

          Class 文件是類文件

          正如前面討論過(guò)的,我的第一個(gè)選項(xiàng)可能只是用 groovyc 編譯腳本。在這個(gè)例子中,我期望 groovyc 創(chuàng)建 至少 兩個(gè) .class 文件 —— 一個(gè)用于 Song 類,另一個(gè)用于 Song 聲明之后的腳本代碼。

          實(shí)際上,groovyc 可能創(chuàng)建 5 個(gè) .class 文件。這是與 Songs.groovy 包含三個(gè)閉包有關(guān),兩個(gè)閉包在 getSongsForDirectory() 方法中,另一個(gè)在腳本體中,我在腳本體中對(duì) Song 的集合進(jìn)行迭代,并調(diào)用 println

          因?yàn)?.class 文件中有三個(gè)實(shí)際上是 Song.class 和 Songs.class 的內(nèi)部類,所以我只需要把注意力放在兩個(gè) .class 文件上。Song.class 直接映射到 Groovy 腳本中的 Song 聲明,并實(shí)現(xiàn)了 GroovyObject,而 Songs.class 則代表我在定義 Song 之后編寫(xiě)的代碼,所以也擴(kuò)展了 Script

          此時(shí)此刻,關(guān)于如何把新編譯的 Groovy 代碼集成到 Java 代碼,我有兩個(gè)選擇:可以通過(guò) Songs.class 文件中的 main() 方法運(yùn)行代碼 (因?yàn)樗鼣U(kuò)展了 Script),或者可以將 Song.class 包含到類路徑中,就像在 Java 代碼中使用其他對(duì)象一樣使用它。

          回頁(yè)首

          變得更容易些

          通過(guò) java 命令調(diào)用 Songs.class 文件非常簡(jiǎn)單,只要您記得把 Groovy 相關(guān)的依賴關(guān)系和 Groovy 腳本需要的依賴關(guān)系包含進(jìn)來(lái)就可以。把 Groovy 需要的類全都包含進(jìn)來(lái)的最簡(jiǎn)單方法就是把包含全部?jī)?nèi)容的 Groovy 可嵌入 jar 文件添加到類路徑中。在我的例子中,這個(gè)文件是 groovy-all-1.0-beta-10.jar。要運(yùn)行 Songs.class,需要記得包含將要用到的 MP3 庫(kù)(jid3lib-0.5.jar>),而且因?yàn)槲沂褂?nbsp;AntBuilder,所以我還需要在類路徑中包含 Ant。清單 4 把這些放在了一起:


          清單 4. 通過(guò) Java 命令行調(diào)用 Groovy
          c:\dev\projects>java -cp  ./target/classes/;c:/dev/tools/groovy/   groovy-all-1.0-beta-10.jar;C:/dev/tools/groovy/ant-1.6.2.jar;   C:/dev/projects-2.0/jid3lib-0.5.jar     com.vanward.groovy.Songs c:\dev09\music\mp3s Artist: U2 Album: Zooropa Song: Babyface Artist: James Taylor Album: Greatest Hits Song: Carolina in My Mind Artist: James Taylor Album: Greatest Hits Song: Fire and Rain Artist: U2 Album: Zooropa Song: Lemon Artist: James Taylor Album: Greatest Hits Song: Country Road Artist: James Taylor Album: Greatest Hits Song: Don't Let Me    Be Lonely Tonight Artist: U2 Album: Zooropa Song: Some Days Are Better Than Others Artist: Paul Simon Album: Graceland Song: Under African Skies Artist: Paul Simon Album: Graceland Song: Homeless Artist: U2 Album: Zooropa Song: Dirty Day Artist: Paul Simon Album: Graceland Song: That Was Your Mother 

          回頁(yè)首

          把 Groovy 嵌入 Java 代碼

          雖然命令行的解決方案簡(jiǎn)單有趣,但它并不是所有問(wèn)題的最終解決方案。如果對(duì)更高層次的完善感興趣,那么可能將 MP3 歌曲工具直接導(dǎo)入 Java 程序。在這個(gè)例子中,我想導(dǎo)入 Song.class ,并像在 Java 語(yǔ)言中使用其他類那樣使用它。類路徑的問(wèn)題與上面相同 :我需要確保包含了 uber-Groovy jar 文件、Ant 和 jid3lib-0.5.jar 文件。在清單 5 中,可以看到如何將 Groovy MP3 工具導(dǎo)入簡(jiǎn)單的 Java 類中:


          清單 5. 嵌入的 Groovy 代碼
          package com.vanward.gembed; import com.vanward.groovy.Song; import java.util.Collection; import java.util.Iterator; public class SongEmbedGroovy{  public static void main(String args[]) {   Collection coll = (Collection)Song.getSongsForDirectory     ("C:\\music\\temp\\mp3s");   for(Iterator it = coll.iterator(); it.hasNext();){     System.out.println(it.next());   }	  } } 

          回頁(yè)首

          Groovy 類加載器

          就在您以為自己已經(jīng)掌握全部的時(shí)候,我要告訴您的是,還有更多在 Java 語(yǔ)言中使用 Groovy 的方法。除了通過(guò)直接編譯把 Groovy 腳本集成到 Java 程序中的這個(gè)選擇之外,當(dāng)我想直接嵌入腳本時(shí),還有其他一些選擇。

          例如,我可以用 Groovy 的 GroovyClassLoader ,動(dòng)態(tài)地 加載一個(gè)腳本并執(zhí)行它的行為,如清單 6 所示:


          清單 6. GroovyClassLoader 動(dòng)態(tài)地加載并執(zhí)行 Groovy 腳本
          package com.vanward.gembed; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyObject; import groovy.lang.MetaMethod; import java.io.File; public class CLEmbedGroovy{  public static void main(String args[]) throws Throwable{     ClassLoader parent = CLEmbedGroovy.class.getClassLoader();   GroovyClassLoader loader = new GroovyClassLoader(parent);      Class groovyClass = loader.parseClass(     new File("C:\\dev\\groovy-embed\\src\\groovy\\       com\\vanward\\groovy\\Songs.groovy"));      GroovyObject groovyObject = (GroovyObject)      groovyClass.newInstance();      Object[] path = {"C:\\music\\temp\\mp3s"};   groovyObject.setProperty("args", path);   Object[] argz = {};      groovyObject.invokeMethod("run", argz);    } } 

          Meta,寶貝

          如果您屬于那群瘋狂的人中的一員,熱愛(ài)反射,喜歡利用它們能做的精彩事情,那么您將熱衷于 Groovy 的 Meta類。就像反射一樣,使用這些類,您可以發(fā)現(xiàn)GroovyObject 的各個(gè)方面(例如它的方法),這樣就可以實(shí)際地 創(chuàng)建 新的行為并執(zhí)行它。而且,這是 Groovy 的核心 —— 想想運(yùn)行腳本時(shí)它將如何發(fā)威吧!

          注意,默認(rèn)情況下,類加載器將加載與腳本名稱對(duì)應(yīng)的類 —— 在這個(gè)例子中是 Songs.class,而不是 Song.class>。因?yàn)槲遥ê湍┲?Songs.class 擴(kuò)展了 Groovy 的 Script 類,所以不用想也知道接下來(lái)要做的就是執(zhí)行 run() 方法。

          您記起,我的 Groovy 腳本也依賴于運(yùn)行時(shí)參數(shù)。所以,我需要恰當(dāng)?shù)嘏渲?nbsp;args 變量,在這個(gè)例子中,我把第一個(gè)元素設(shè)置為目錄名。

          回頁(yè)首

          更加動(dòng)態(tài)的選擇

          對(duì)于使用編譯好的類,而且,通過(guò)類加載器來(lái)動(dòng)態(tài)加載 GroovyObject 的替代,是使用 Groovy 優(yōu)美的 GroovyScriptEngine 和GroovyShell 動(dòng)態(tài)地執(zhí)行 Groovy 腳本。

          把 GroovyShell 對(duì)象嵌入普通 Java 類,可以像類加載器所做的那樣動(dòng)態(tài)執(zhí)行 Groovy 腳本。除此之外,它還提供了大量關(guān)于控制腳本運(yùn)行的選項(xiàng)。在清單 7 中,可以看到 GroovyShell 嵌入到普通 Java 類的方式:


          清單 7. 嵌入 GroovyShell
          package com.vanward.gembed; import java.io.File; import groovy.lang.GroovyShell; public class ShellRunEmbedGroovy{  public static void main(String args[]) throws Throwable{ 						   String[] path = {"C:\\music\\temp\\mp3s"};		   GroovyShell shell = new GroovyShell();   shell.run(new File("C:\\dev\\groovy-embed\\src\\groovy\\     com\\vanward\\groovy\\Songs.groovy"),      path);  } } 

          可以看到,運(yùn)行 Groovy 腳本非常容易。我只是創(chuàng)建了 GroovyShell 的實(shí)例,傳遞進(jìn)腳本名稱,然后調(diào)用 run() 方法。

          還可以做其他事情。如果您喜歡,那么也可以得到自己腳本的 Script 類型的 GroovyShell 實(shí)例。使用 Script 類型,您就可以傳遞進(jìn)一個(gè) Binding 對(duì)象,其中包含任何運(yùn)行時(shí)值,然后再繼續(xù)調(diào)用 run() 方法,如清單 8 所示:


          清單 8. 有趣的 GroovyShell
          package com.vanward.gembed; import java.io.File; import groovy.lang.Binding; import groovy.lang.GroovyShell; import groovy.lang.Script; public class ShellParseEmbedGroovy{  public static void main(String args[]) throws Throwable{   GroovyShell shell = new GroovyShell();   Script scrpt = shell.parse(     new File("C:\\dev\\groovy-embed\\src\\groovy\\       com\\vanward\\groovy\\Songs.groovy"));      Binding binding = new Binding();   Object[] path = {"C:\\music\\temp\\mp3s"};   binding.setVariable("args",path);			   scrpt.setBinding(binding);      scrpt.run();  } } 

          回頁(yè)首

          Groovy 的腳本引擎

          GroovyScriptEngine 對(duì)象動(dòng)態(tài)運(yùn)行腳本的時(shí)候,非常像 GroovyShell。區(qū)別在于:對(duì)于 GroovyScriptEngine,您可以在實(shí)例化的時(shí)候給它提供一系列目錄,然后讓它根據(jù)要求去執(zhí)行多個(gè)腳本,如清單 9 所示:


          清單 9. GroovyScriptEngine 的作用
          package com.vanward.gembed; import java.io.File; import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; public class ScriptEngineEmbedGroovy{  public static void main(String args[]) throws Throwable{ 			   String[] paths = {"C:\\dev\\groovy-embed\\src\\groovy\\     com\\vanward\\groovy"};   GroovyScriptEngine gse = new GroovyScriptEngine(paths);   Binding binding = new Binding();   Object[] path = {"C:\\music\\temp\\mp3s"};   binding.setVariable("args",path);      gse.run("Songs.groovy", binding);   gse.run("BusinessObjects.groovy", binding);  } } 

          在清單 9 中,我向?qū)嵗?nbsp;GroovyScriptEngine 傳入了一個(gè)數(shù)組,數(shù)據(jù)中包含我要處理的路徑,然后創(chuàng)建大家熟悉的 Binding 對(duì)象,然后再執(zhí)行仍然很熟悉的 Songs.groovy 腳本。只是為了好玩,我還執(zhí)行了BusinessObjects.groovy 腳本,您或許還能回憶起來(lái),它在開(kāi)始這次討論的時(shí)候出現(xiàn)過(guò)。

          回頁(yè)首

          Bean 腳本框架

          最后,當(dāng)然并不是最不重要的,是來(lái)自 Jakarta 的古老的 Bean 腳本框架( Bean Scripting Framework —— BSF)。BSF 試圖提供一個(gè)公共的 API,用來(lái)在普通 Java 應(yīng)用程序中嵌入各種腳本語(yǔ)言(包括 Groovy)。這個(gè)標(biāo)準(zhǔn)的、但是有爭(zhēng)議的最小公因子方法,可以讓您毫不費(fèi)力地將 Java 應(yīng)用程序嵌入 Groovy 腳本。

          還記得前面的 BusinessObjects 腳本嗎?在清單 10 中,可以看到 BSF 可以多么容易地讓我把這個(gè)腳本插入普通 Java 程序中:


          清單 10. BSF 開(kāi)始工作了
          package com.vanward.gembed; import org.apache.bsf.BSFManager; import org.codehaus.groovy.runtime.DefaultGroovyMethods; import java.io.File; import groovy.lang.Binding; public class BSFEmbedGroovy{  public static void main(String args[]) throws Exception {   String fileName = "C:\\dev\\project\\src\\groovy\\     com\\vanward\\groovy\\BusinessObjects.groovy";   //this is required for bsf-2.3.0   //the "groovy" and "gy" are extensions   BSFManager.registerScriptingEngine("groovy",      "org.codehaus.groovy.bsf.GroovyEngine", new        String[] { "groovy" });   BSFManager manager = new BSFManager();   //DefaultGroovyMethods.getText just returns a    //string representation of the contents of the file   manager.exec("groovy", fileName, 0, 0,      DefaultGroovyMethods.getText(new File(fileName)));   } } 

          回頁(yè)首

          結(jié)束語(yǔ)

          如果在本文中有一件事是清楚的話,那么只件事就是 Groovy 為了 Java 代碼內(nèi)部的重用提供了一堆選擇。從把 Groovy 腳本編譯成普通 Java .class 文件,到動(dòng)態(tài)地加載和運(yùn)行腳本,這些問(wèn)題需要考慮的一些關(guān)鍵方面是靈活性和耦合。把 Groovy 腳本編譯成普通 .class 文件是 使用 您打算嵌入的功能的最簡(jiǎn)單選擇,但是動(dòng)態(tài)加載腳本可以使添加或修改腳本的行為變得更容易,同時(shí)還不必在編譯上犧牲時(shí)間。(當(dāng)然,這個(gè)選項(xiàng)只是在接口不變的情況下才有用。)

          把腳本語(yǔ)言嵌入普通 Java 不是每天都發(fā)生,但是機(jī)會(huì)確實(shí)不斷出現(xiàn)。這里提供的示例把一個(gè)簡(jiǎn)單的目錄搜索工具嵌入到基于 Java 的應(yīng)用程序中,這樣 Java 應(yīng)用程序就可以很容易地變成 MP3 播放程序或者其他 MP3 播放工具。雖然我 可以 用 Java 代碼重新編寫(xiě) MP3 文件搜索器,但是我不需要這么做:Groovy 極好地兼容 Java 語(yǔ)言,而且,我很有興趣去擺弄所有選項(xiàng)!


          參考資料

          關(guān)于作者

          Andrew Glover 是 Vanward Technologies 的 CTO,該公司位于華盛頓特區(qū)大都會(huì)地區(qū),專門(mén)進(jìn)行自動(dòng)測(cè)試工作和框架的構(gòu)建,自動(dòng)測(cè)試工作和框架可以降低軟件 bug 的數(shù)量,減少集成和測(cè)試時(shí)間,提高整體的代碼穩(wěn)定性。Andrew Glover 還是 Java Testing Patterns (Wiley,2004 年 9 月)一書(shū)的合著者之一。



          posted on 2011-11-10 05:45 hk2000c 閱讀(745) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 平潭县| 达日县| 阳曲县| 安乡县| 南丰县| 阿勒泰市| 宁武县| 杨浦区| 大姚县| 牟定县| 蓬安县| 陕西省| 南陵县| 芜湖市| 彩票| 南郑县| 新乡县| 桐城市| 内丘县| 苍溪县| 霸州市| 巴南区| 隆化县| 宣恩县| 逊克县| 布拖县| 时尚| 北宁市| 湖口县| 沙坪坝区| 双江| 阿鲁科尔沁旗| 呼和浩特市| 山东省| 象州县| 潍坊市| 峡江县| 五寨县| 乌兰察布市| 饶阳县| 星座|