包名
當你在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中腳本和類的關系了,更多詳細內容請參考: