Groovy中的腳本與類

包名

當你在groovy中定義類的時候須要指定包名,這和java中相似很少介紹。html

導入

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

默認導入

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

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

普通導入

普通導入即全類名導入github

// 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是能夠同時支持編寫腳本和類的,接下來就來學習一下他們之間的關係。ui

先看下面的例子this

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

這是java的傳統寫法,這裏把須要執行的代碼寫在了main中,在groovy中達到一樣的效果就簡單多了:.net

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中腳本和類的關係了,更多詳細內容請參考:

相關文章
相關標籤/搜索