Groovy
圖譜:Spark<-Scala<-Gradle<-Groovy
Before you learn, setup your IDE well!!! IDEA is recommanded.
1. Groovy基于JVM;
2.如果把java文件的后綴改成.groovy,能夠編譯通過并運行。但是由于groovy是動態語言,很多行為可能會不一致。尤其涉及繼承、多態的時候。如果調用方使用的是父類,則,java會找一個最上層的基類實現,但是groovy則會使用實際的對象中的方法。例如下面的代碼中,如果是java,則在collection.remove中,實際調用的是Collection的直接子類AbstractCollection的remove方法,嘗試將0轉成Object去刪除,但是Collection中沒有Integer(0)這個對象,所以沒有刪除。Java并不會把0當做index。而對于groovy,即使使用的是collection.remove,groovy也會使用實際對象的類型中的remove,也就是ArrayList的remove,把0當做index。執行這段代碼后,java會剩一個元素,groovy集合為空。
ArrayList<String> list=new ArrayList<>();
Collection<String> collection=list;
list.add("Jim");
list.add("Tom");
collection.remove(0);
list.remove(0);
3. groovy聲明對象時,可以指定類型,但是和java不同,groovy并不在靜態時檢查這個類型,而是在運行時嘗試做強制類型轉換。因此是偽靜態類型。groovy可以使用注解來執行更嚴格的編譯時檢查:
@groovy.transform.TypeChecked
def shout(String str){
str.notExistMethod();
}
4. 動態語言沒有編譯時類型檢查,甚至連方法、屬性是否存在也不能確定,也不能幫助發現一些拼寫錯誤。為了保障程序的功能能夠正常實現,應該采用完整的ut來驗證功能。動態語言對ut的要求更加嚴格。
5. 可以使用@CompileStatic讓groovy執行靜態編譯,但是會失去元編程的能力,這主要是出于性能考慮。groovy動態編譯可能導致損失10%的性能,但是靜態編譯可以產生和java相媲美的性能。
6. 閉包
def each(n, block){
for(int i=0;i<n;++i){
block(i)
}
}
each(10, { it -> println it }) <=> each(10, { println it }) <=> each(10){ println it }
def examine(closure){
println closure.maximumNumberOfParameters
}
examine(){} // closure.maximumNumberOfParameters = 1
examine(){it} // closure.maximumNumberOfParameters = 1
examine(){->} // closure.maximumNumberOfParameters = 0
7. 科里化(咖喱化,哈哈)
add3 = { x, y, z = x + y + z }
add2 = add3.curry(1)
add = add2.curry(2)
addr = add3.rcurry(5) // <=> add3(x, y, 5)
addn = add3.ncurry(1, 9) // <=> add3(x, 9, z)
add3.call(4, 5, 6) <=> add3(4, 5, 6)
add(3) //6
8. GDK
Groovy 給java.lang.Object增加了一些方法。還有更多,例如use,mixin 等都在 DefaultGroovyMethods 中定義。
obj.dump()
obj.inspect();
list=[]; list.add(3); list.add(4) <=> list=[]; list.with(add(3);add(4));
9. 一個簡單的DSL, 放在Counter.groovy中可以直接運行。以get set開頭的方法是定義了類的屬性訪問器。
value = 10
def getClear() {
value = 0
}
def getTotal() {
println "Total count is ${value}"
}
def add(int n) {
value += n
}
clear
add 3
total
add 4
total
clear
total
10. this, delegate和owner
this 指閉包本身;owner指定義閉包的外層閉包;默認delegate和owner相等,但是delegate可以被修改。
List.metaClass.myeach={delegate.each{println it}}
11. MOP(MetaObject Protocol) 和元編程
Groovy對象分為三種:
POJO普通java對象
POGO使用Groovy編寫的對象,擴展了java.lang.Object 對象,同時實現了groovy.lang.GroovyObject接口。一旦一個類被加載到JVM中,我們就不能修改它的元對象Class了,但是我們可以通過setMetaClass修改它的MetaClass,造成一種對象運行時類被修改了的感覺。
package groovy.lang;
public interface GroovyObject {
Object invokeMethod(String var1, Object var2);
Object getProperty(String var1);
void setProperty(String var1, Object var2);
MetaClass getMetaClass();
void setMetaClass(MetaClass var1);
}
Groovy攔截器 是擴展了GroovyInterceptable接口的Groovy對象。不管對象存在的還是不存在的方法調用,都會被它的invokeMethod攔截。對于一般的groovy對象時只有當方法不存在時,才會調用的invokeMethod方法,除非在對象的MetaClass上實現了InvokeMethod方法
package groovy.lang;
public interface GroovyInterceptable extends GroovyObject {
}
Groovy對調用方法的路由:
1)如果是POJO對象,先從MetaClassRegistry中取出MetaClass,并將方法代理給它。因此在MetaClass上定義的任何方法都先于POJO自己定義的方法
2)如果是POGO對象,且實現了GroovyInterceptable接口,所有的調用都會被路由到invokeMethod方法,在這個攔截器內,調用正確的方法,使得AOP成為可能。
3)如果是POGO對象,沒有實現GroovyInterceptable,則會先查找MetaClass中定義的方法,如果沒有找到,就調用POGO本身的方法。如果POGO沒有這樣的方法,會查找POGO的屬性或者字段。如果屬性或者字段是Closure類型,則調用它以代替方法調用。接下來會嘗試調用methodMissing方法,否則調用invokeMethod方法。invokeMethod的默認實現是拋出MethodMissingException。其中invokeMethod和methodMissing必須有嚴格的prototype聲明。一下還給出了調用默認實現的一個invokeMethod的實現。
def invokeMethod(String method, Object args){ metaClass.getMetaMethod(method, args).invoke(this, args) //metaClass.invokeMethod(this, method, args); }
查看某個方法能否被相應
String.metaClass.respondsTo(str,"compareTo","test") // true
12. MOP 方法注入的三種方式
1) 分類。背后的原理是調用GroovyCategorySupport.use(categoryClass, closure)方法,創建臨時作用域,將新方法附在目標對象的MetaClass上。一旦閉包結束,則丟棄所有加入的新方法。也可以使用@Category注解來實現。
class StringUtil {
def static dup(str) {
str + str
}
}
use(StringUtil) {
println "hello,".dup()
}
2) ExpandoMetaClass
向類的MetaClass添加新方法,這樣會將累的MetaClass從MetaClassImpl變成ExpandoMetaClass。可以通過<< 添加新的構造函數。改變某個對象的MetaClass而不是整個類。這個像極了js
def jack = new Person()
def emc = new ExpandoMetaClass(Person)
emc.sing = {-> "Sing..."}
emc.initialize()
jack.metaClass = emc
println jack.sing()
jack.metaClass=null //去除添加在metaClass上的方法
3) Mixin
class Friend{
def sayHello(){
println "Hello, $name!"
}
}
/**************************************/
@Mixin(Friend)
class Person{
def name
Person(){
name="Jim"
}
}
new Person().sayHello()
/**************************************/
Person.mix Friend
new Person().sayHello()
/**************************************/
def person = new Person()
person.metaClass.mix Friend
person.sayHello()
13. 動態創建類:Expando,這個仍然像極了js
def car = new Expando(mile: 300, turn:{dir -> println "turning $dir"})
car.color = "green"
14. 在java/groovy中使用java類,groovy類和groovy腳本
1) 運行groovy腳本
groovy script.groogy //run directly
groovyc script.groovy // compile first, generate script.class
groovy -cp . script // run the groovy class
2) groovy中使用java
groovyc -j Animal.java useAnimal.groovy // outputs Animal.class, useAnimal.class
groovy -cp . useAnimal
也可以使用javac自行對java文件進行編譯生成class文件,將生成的class文件加入到groovy的classpath中即可。畢竟groovy的類中包含POJO,POGO,Interceptable,groovy可以正確處理POJO。
3)java中使用groovy靜態方法
// Function.groovy
class Function{
def apply(v,closure){
closure(v)
}
}
//Main.java
public class Main{
public static void main(String[] args){
System.out.println(new Function().apply(3, new Object(){
public int call(int v){
return v * 2;
}
}));
}
}
groovyc -j Main.java Function.groovy // compile
java -cp groovy-3.0.0-alpha-3/lib/groovy-3.0.0-alpha-3.jar: Main // run
4) Java中使用groovy的動態方法
只需要將產生的對象賦值給 groovy.lang.GroovyObject,然后調用該對象的invokeMethod方法即可。
5) Groovy中使用groovy腳本 需要使用GroovyShell,使用Binding傳遞參數,使用run來傳遞命令行參數
6) Java 中使用Groovy腳本 需要使用javax.script.ScriptEngineManager和ScriptEngine
Questions
1. Groovy中callsite的概念。腳本會被轉化成Call site,機制是什么?
2. Groovy可以修改metaClass,這個是如何存儲的?這部分可能需要明白JVM的編譯和反編譯機制。
智能推薦
Groovy_Learn_003_Groovy基本語法
Groovy基本語法 為了了解Groovy的基本語法,讓我們先看一個簡單的Hello World程序 在Groovy中導入語句import語句可以用來導入,可以在你的代碼可以使用其他庫的功能。這是通過使用在 Import 關鍵字完成。 下面的示例演示了如何使用MarkupBuilder的類,它可能是最常用的創建HTML或XML標記的類之一。 默認情況下,Groovy在代碼中包括以下庫,因此您不需要...
Groovy_Learn_002_Groovy環境
Groovy環境 有多種方式來獲得Groovy環境設置 下載安裝,獲得Windows安裝部分 ----- 安裝過程就不詳細的介紹了。 也可下載壓縮包 下載后,把壓縮包解壓到相應的位置,然后再環境變量的Path里面添加解壓后的路徑(到解壓的bin目錄下)。配置好后,然后運行groovy -v,可以看到如下圖 到這里,就安裝好了。 Hello Groovy Dos中運行groovyconsole之后,...
Linux下安裝groovy & Idea安裝groovy
1.下載groovy-2.5.3 下載鏈接:某盤鏈接 提取碼:q3ir 如果鏈接失效,請留言。 2.Linux安裝groovy 3.Idea安裝groovy 下載groovy-2.5.3.zip后,本地解壓縮,記住路徑,如:/Download/groovy-2.5.3 打開Idea,右鍵項目,選擇Project Structure -> Global Libraries -> 加號 -...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...