Groovy

Groovy基于Java语言,兼容Java语法,他其实就是一种较为系统的java语法糖,既可以作为面向对象编程语言,也可以作为脚本语言。

基础语法

Groovy Script 和 Groovy Object

作为脚本时,Groovy脚本文件中的所有脚本命令将会生成一个Java Class,并继承groovy.lang.Script类。

比如如下脚本 Hello.groovy

print("hello world")

将会生成一个与脚本文件名称相同的类,这里是Hello.class

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

// 继承Script,并提供一个 main 方法
public class Demo01 extends Script {
    public Demo01() {
        CallSite[] var1 = $getCallSiteArray();
        super();
    }

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

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

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

不仅如此,在一个Groovy文件中可以混合类定义与脚本定义,但是脚本名不可以与脚本中定义的类名相同,因为脚本类也会生成Class,Class是不可以重名的。

如下代码是一个混合脚本,除了Hello.class,还会生成一个Person.class

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import groovy.transform.Internal;
import java.beans.Transient;
import org.codehaus.groovy.runtime.callsite.CallSite;

// Groovy 的class 默认实现 GroovyObject 接口
public class Person implements GroovyObject {
    @Generated
    public Person() {
        CallSite[] var1 = $getCallSiteArray();
        super();
        MetaClass var2 = this.$getStaticMetaClass();
        this.metaClass = var2;
    }

    @Generated
    @Internal
    @Transient
    public MetaClass getMetaClass() {
        MetaClass var10000 = this.metaClass;
        if (var10000 != null) {
            return var10000;
        } else {
            this.metaClass = this.$getStaticMetaClass();
            return this.metaClass;
        }
    }

    @Generated
    @Internal
    public void setMetaClass(MetaClass var1) {
        this.metaClass = var1;
    }
}

使用def定义变量

Groovy提供关键字def用于定义变量,他是一种动态类型机制,也就是说,在运行时才会去校验数据类型;而静态类型是在编译时对数据类型进行校验检查。

def s = "hello"

分号可以用换行替换

print("hello world")
print("hello world")

类、成员默认全是public的

Java类、以及类中的成员,默认修饰级别为default,而Groovy中默认则是public的:

public class Person{}
class Person{}

上面两个代码是相同的。

类中的属性会自动添加getter和setter

class Person {
    def name
    def age
    def hobby
}

def p = new Person()
println(p.getHobby())

对象的属性操作

// 创建对象
def p = new Person()

// 使用属性名直接给成员赋值
p.name = "张三"
p["age"] = 20
// 使用setter方法赋值
p.setHobby("打篮球")

// 使用属性名读取属性值
println(p.name)
println(p["age"])
// 使用getter方法获取
println(p.getHobby())

无论是哪儿种方式,实际上最终仍然是调用的getter和setter

创建对象使用构造器指定属性值

def p = new Person(name: "张三", age: 12)

方法的定义

声明方法时,参数类型可省略:

String getHelloStr(String name) {
    return "hello " + name
}
println getHelloStr("张三")

// 方法的返回值与参数类型可以使用def代替
def getHelloStr1(def name) {
    return "hello " + name
}
println getHelloStr1("张三")

// 方法的参数类型可以不写
def getHelloStr2(name) {
    return "hello " + name
}
println getHelloStr2("张三")

// renturn 关键字可以省略
def getHelloStr3(name) {
    "hello ${name}"
}
println getHelloStr3("张三")

方法的调用可以省略()

当不引起歧义的时候,方法调用的小括号可以省略,下面两行代码是相同的:

println "hello world"
println("hello world")

在Groovy中没有基本类型,字面量可以直接调用包装类型方法

def one = 1.longValue()

三种字符串表示

  • 单引号:字符串常量,不具有运算能力,会被解析为 java.lang.String

  • 双引号:可引用变量${},具有运算能力,会被解析为 GStringImpl

  • 三引号:支持换行,会被解析为java.lang.String

def name = '张三'

def sayhello = "你好,${name}"
// 在不引起歧义的情况下可省略大括号
sayHello = "你好, $name";

def str = '''
多行字符串
支持换行
**不支持**引用变量 ${name}
'''

自动类型转换

在需要的时候,类型之间会自动发生类型转换。

控制语句

控制语句基本与java相同。

闭包

定义:开放的、匿名的代码块,他可以接收参数,也可以有返回值。闭包还可以引用其周围作用域中声明的变量。

语法:

{
    [closureParameters ->] statements
}

使用闭包需要:

1. 将闭包赋值给一个变量
2. 使用 `变量名()` 或者 `变量名.call()` 调用闭包

> 开发中通常将闭包作为方法参数调用

示例:

```groovy
def helloWorld = {
    println "hello world"
}
helloWorld()

def hello = {
    name -> println "hello $name"
}
hello.call("张三")

def run(Closure closure) {
    closure();
}
run({println("run!!!")})

def caculate(num1, num2, Closure closure) {
    closure(num1, num2)
}
caculate(10, 15, {k, v -> println("$k + $v = ${k+v}")})

// 如果闭包方法的最后一个参数,那么调用时,可以将闭包这个参数写在方法外面
caculate(10, 15) {k, v -> println("$k + $v = ${k+v}")}

最后更新于