• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 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的編譯和反編譯機制。

    版權聲明:本文為zhshuai1原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/zhshuai1/article/details/82250567

    智能推薦

    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 -> 加號 -...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    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 以上述例子,判斷一個生產出...

    精品国产乱码久久久久久蜜桃不卡