在JVM中运行groovy类有两种方式:
使用groovyc编译所有的*.groovy为java的*.class文件,把这些*.class文件放在java类路径中,通过java类加载器来加载这些类。
通过groovy的类加载器在运行时直接加载*.groovy文件并且生成对象,在这种方式下,没有生成任何*.class,但是生成了一个java.lang.Class对象的实例。(java的动态编译加载功能)
groovy在源代码级增强java,但是在字节码是与java一样的。
Groovy的语法是面向行的,但是执行groovy代码却不是这样的,不像别的脚本语言,groovy代码不是一行一行的解释执行的。
groovy代码被完整地转换,通过转换器产生一个java类,产生的这个类是groovy和java之间的粘合剂。产生的groovy类的格式与java字节码的格式是一样的。
groovy的类加载器能够从*.groovy文件加载类(在放入缓存之前进行转换和生成类)。
在运行时生成groovy类
1.MyScript.groovy被传递给groovy的转换器
2.转换器产生一个抽象语法树(AST)来表示在MyScript.groovy中的所有代码;
3.Groovy类生成器根据AST产生java字节码,根据脚本的内容,结果可能是多个类,现在类通过groovy类加载器是可以使用的了;
4.Java运行时像调用一个java类MyScript一样来调用第三步产生的类;
在使用之前类已经完整地构建并且在运行时不能进行更改(不排除在.groovy被修改之后对类在运行时的替换)。
groovy中一切事情都是对象,所有的操作符都是作为方法调用进行处理的。
注意BigDecimal是默认的非整数类型——除非指定后缀强制类型为Float或者Double,否则将使用BigDecimal。
给定期望信息的时候groovy是如何处理类型的:
在groovy中出现的字面符号(数字、字符串等等)没有任何问题,它们都是对象,它们仅仅传递给java时才进行装箱和拆箱,操作符是方法调用的快速途径。
操作符是方法的便利写法(在groovy中所有的都是对象,操作符是对象方法的便利写法):
“==”或者equals指示对象是否同等(值相等),而不是是否指向同一个对象。
实现equals的目的是保证这个对象可以与null对象进行对比。equals操作的缺省实现是不抛出NullPointerException。
times方法仅仅用于做重复的动作,upto方法是递增一个数字,downto是递减一个数字,step是按一个步进从一个数递增到另外一个数。
在面向对象语言,方法对象模式(Method-Object-pattern)通常用来模拟一个行为:为一个目的定义一个独立的方法接口,这个接口的实例能够传递一组参数给方法,然后调用这个接口方法。
一个闭包是一个用花括号围起来的语句块,为了传递参数给闭包,闭包有一组可选的参数列表,通过“->”表示列表的结束。
脚本允许使用没有声明的变量,在这种情况下变量被假定从脚本的binding属性获取,如果在binding中没有发现相应的变量,那么把变量增加到bindding中,binding是一个数据存储器,它能把变量在脚本调用者和脚本之间进行传递。
缺省属性范围在groovy有特殊的意思,在没有指定范围修饰符的属性声明的时候,groovy会根据需要生成相应的访问方法(getter方法和setter方法)
定义变量的类型是可选的,不管怎样,标示符在声明的时候不必独一无二,当没有类型和修饰符时,必须使用def来作为替换,实际上用def来表明属性或者变量是没有类型的(尽管在内部将被声明为Object类型)。
重写下标操作符:
重写get方法意味着重写了dot-fieldName操作符,重写了set方法意味着重写了field assignment操作符。
class PretendFieldCounter{
public count = 0;
Object get(String name){
return 'pretend value';
}
void set(String name,Object value){
count++
}
}
class Test {
static main(args) {
def pretender = new PretendFieldCounter();
println pretender.isNoField == 'pretend value';
println pretender.count == 0;
pretender.isNoFieldEither = 'just to increase counter'
println pretender.count == 1
}
}
结果全都是true
第五章闭包
一个闭包是被包装为一个对象的代码块,实际上闭包像一个可以接受参数并且能够有返回值的方法。
闭包是一个普通对象。
闭包的简短写法:
class Closure {
static main(args) {
Closure envelope = {person-> printf(person)}
["a","b"].each(envelope);
}
}
可以写成如下形式:
class Closure2 {
static main(args) {
["a","b"].each{printf(it)};
}
}
使用闭包作为单个参数的方法调用(在groovy中传递一个闭包给一个方法是非常平常,没有特殊规则。)
声明闭包
def printer = {line -> println line}
通过方法的返回值
def Closure getPrinter(){
return {line -> println line}
}

调用闭包:
class CallingClosures {
static main(args) {
def adder = {x,y -> return x+y}
assert adder(4,3) == 7
assert adder.call(2,6) == 8
}
}
class Closure4 {
static main(args) {
def adder = {x,y=5 -> return x+y}
assert adder(4,3) == 7
assert adder.call(7) ==12
}
}
闭包典型的调用方式:

class Closure5 {
def caller(def closure){
closure.getParameterTypes().size()
}
void test(){
assert caller{ one ->} ==1
assert caller{ one,two ->} ==2
}
static main(args) {
new Closure5().test()
}
}
curry函数(函数式编程)
class Closure6 {
static main(args) {
def configurator = { format,filter,line->
filter(line)? format(line):null
}
def appender = {config,append,line ->
def out = config(line)
if(out) append(out)
}
def dateFormatter = {line -> "${new Date()}:$line"}
def debugFilter = { line -> line.contains('debug')}
def consoleAppender = { line -> println line}
def myConf = configurator.curry(dateFormatter,debugFilter)
def myLog = appender.curry(myConf,consoleAppender)
myLog('here is some debug message')
myLog('this will not be printed')
}
}
通过isCase方法进行分类
class Closure7 {
static main(args) {
assert [1,2,3].grep{ it < 3} == [1,2]
switch(10){
case {it%2 == 1} : assert false
}
}
}
花括号显示了闭包声明的时间,不是执行的时间