Groovy中的腳本與類


包名

當你在groovy中定義類的時候需要指定包名,這和java中類似不多介紹。

導入

groovy中的導入也跟java類似,有一下五種:

默認導入

groovy默認導入了一下幾個包和類:

import java.lang.*
import java.util.*
import java.io.*
import java.net.*
import groovy.lang.*
import groovy.util.*
import java.math.BigInteger
import java.math.BigDecimal

普通導入

普通導入即全類名導入

// importing the class MarkupBuilder
import groovy.xml.MarkupBuilder

// using the imported class to create an object
def xml = new MarkupBuilder()

assert xml != null

包導入

這個也不用多說

import groovy.xml.*

def markupBuilder = new MarkupBuilder()

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

靜態導入

import static java.lang.String.format 

class SomeClass {

    String format(Integer i) { 
        i.toString()
    }

    static void main(String[] args) {
        assert format('String') == 'String' 
        assert new SomeClass().format(Integer.valueOf(1)) == '1'
    }
}

靜態簡稱導入

靜態簡稱導入在java中是沒有的,這里解釋一下。Calendar有一個靜態方法getInstance()可以獲得Calendar的實例,既然是靜態方法我們就可以使用上面的靜態導入來直接調用getInstance()方法,但getInstance()這個方法在被調用的時候有誤導性,不清楚的還以為是用於獲得當前類的實例,所以這時候靜態簡稱導入就發揮作用了:

import static Calendar.getInstance as now

assert now().class == Calendar.getInstance().class

這樣我們就直接可以調用now()來獲得Calendar的實例了,這樣是不是清晰了很多?

腳本和類

讀了Groovy基本句法應該了解groovy是可以同時支持編寫腳本和類的,接下來就來學習一下他們之間的關系。

先看下面的例子

class Main {                                    
    static void main(String... args) {          
        println 'Groovy world!'                 
    }
}

這是java的傳統寫法,這里把需要執行的代碼寫在了main中,在groovy中達到同樣的效果就簡單多了:

println 'Groovy world!'

雖然上面的是一行腳本語言,但在運行的時候Groovy還是將其轉換成類來處理,類似如下的類:

Main.groovy

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {                     
    def run() {                                 
        println 'Groovy world!'                 
    }
    static void main(String[] args) {           
        InvokerHelper.runScript(Main, args)     
    }
}

可以看出來需要執行的代碼被放入了run()方法中。

這里我們可以簡單證實一下上面的說法:

首先新建一個main.groovy的腳本文件,內容如下:

println 'hello world !'

接着時候groovyc命令將main.groovy轉換成字節碼main.class,接着使用class文件的閱讀工具查看其內容如下:

	//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class main extends Script {
    public main() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public main(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, main.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        return var1[1].callCurrent(this, "hello world !");
    }
}

雖然生成的和上面略有不同,但的確是被轉換為一個繼承Script的類,而且需要運行的代碼被放在run方法中了。

接下來我們看看腳本中定義的方法會被怎么轉換。

method.groovy

println 'Hello'

int power(int n) { 2**n }

println "2^6==${power(6)}"  

還是按照之前的轉換方法,得到結果:

public class method extends Script {
    public method() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public method(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, method.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        var1[1].callCurrent(this, "Hello");
        return !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()?var1[4].callCurrent(this, new GStringImpl(new Object[]{Integer.valueOf(this.power(6))}, new String[]{"2^6==", ""})):var1[2].callCurrent(this, new GStringImpl(new Object[]{var1[3].callCurrent(this, Integer.valueOf(6))}, new String[]{"2^6==", ""}));
    }

    public int power(int n) {
        CallSite[] var2 = $getCallSiteArray();
        return DefaultTypeTransformation.intUnbox(var2[5].call(Integer.valueOf(2), Integer.valueOf(n)));
    }
}

可以看到power()被定義在了method這個類中。

下來再來看看變量是怎么被轉換的

variables1.groovy

int x = 1
int y = 2
assert x+y == 3

轉換結構如下:

public class variables1 extends Script {
    public variables1() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public variables1(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, variables1.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        byte x = 2;
        byte y = 3;
        return BytecodeInterface8.isOrigInt() && !__$stMC && !BytecodeInterface8.disabledStandardMetaClass()?var1[3].callCurrent(this, Integer.valueOf(x + y)):var1[1].callCurrent(this, var1[2].call(Integer.valueOf(x), Integer.valueOf(y)));
    }
}

可以看出來x,y被定義為了run方法的布局變量。

接着看:

variables2.groovy

x = 2
y = 3
println x+y

轉換結果如下

public class variables2 extends Script {
    public variables2() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public variables2(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, variables2.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        byte var2 = 2;
        ScriptBytecodeAdapter.setGroovyObjectProperty(Integer.valueOf(var2), variables2.class, this, (String)"x");
        byte var3 = 3;
        ScriptBytecodeAdapter.setGroovyObjectProperty(Integer.valueOf(var3), variables2.class, this, (String)"y");
        return var1[1].callCurrent(this, var1[2].call(var1[3].callGroovyObjectGetProperty(this), var1[4].callGroovyObjectGetProperty(this)));
    }
}

額,看不太懂了,但可以肯定x,y沒有被定義成run的成員變量。

綜合上面的兩個變量轉換的例子,請判斷下面這個腳本可以正確執行嗎?

int x = 1;

def getDoubleX(){
    x*2 ;
}

println getDoubleX()

答案是不能,這里的x會被定義成run的成員變量,而getDouble這個方法是訪問不到x的,這里需要注意。

以上就是關於Groovy中腳本和類的關系了,更多詳細內容請參考:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM