- Gradle 之Groovy基本语法(一)
- Gradle 之Groovy文件操作(二)
- Gradle 之详解Project(三)
- Gradle 之详解Task(四)
- Gradle 之初识插件(五)
- Gradle 之常用配置(六)
- Gradle 之扩展Extension类 (七)
一、前言
在做Android开发的时候,IDE是Android Studio,而项目构建是Gradle。Gradle负责将我们写的代码打包成为最终可以执行的东西。在以前的项目构建都是用Ant和Maven等。之前的如Ant、Maven都采用XML配置的方式来构建打包脚本的,Gradle比较强的原因就在于Gradle中使用了Groovy语言,可以编写复杂的功能,这是使用XML很难做到的。
借用百度百科对Groovy的介绍:Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。
从中可以了解,Groovy和Kotlin一样,他们都是基于JVM的语言,这样java和groovy就可以无缝切换了。再者Groovy在结合了其他优秀的语言的特性。第三Groovy是个DSL领域特定语言,不求博只求专,是特长就是写脚本。
使用Groovy前需要有些步骤:
- 下载Groovy sdk并配置环境变量 可见 https://www.jianshu.com/p/777cc61a6202
- 下载一个编写环境软件,我这用的是IDEA
- 新建一个Groovy项目即可
二、Groovy基本对象
1、基本类型
int i = 10
long l = 4l
float f = 4.4f
double d = 3.3d
short s = 2
char c = 'h'
byte b = 0b010101
boolean bool = true
println("i = "+i+" 类型:"+i.getClass())
println("l = "+l+" 类型:"+l.getClass())
println("f = "+f+" 类型:"+f.getClass())
println("d = "+d+" 类型:"+d.getClass())
println("s = "+s+" 类型:"+s.getClass())
println("b = "+b+" 类型:"+b.getClass())
println("c = "+c+" 类型:"+c.getClass())
println("bool = "+bool+" 类型:"+bool.getClass())
groovy的基本类型同java一样,简单就稍微演示了。同java一样虽然是int型的,但通过getClass判断却是Integer类。
- 二进制 0b前缀
- 八进制 0前缀
- 十六进制 0X前缀
2、字符串
Groovy沿用了java中的String对象和自己的GString对象。对于String和java中的一致。
常用的定义方式:
def str1 = '我是\'字符串'
def str2 = "我是'字符串 ${str1}"
def str3 = '''
我是'字符串'''
println("str1 = " + str1+" 类型:"+str1.getClass())
println("str2 = " + str2+" 类型:"+str2.class)
println("str3 = " + str3+" 类型:"+str3.getClass())
- 单引号 和 java中的双引号一致。
- 双引号 可以直接的在中间写特殊的字符而不用加入反斜杠,使用双引号更加的适用于业务
- 三个单引号 这是对双引号的加强版,三个单引号可以使换行处理,属于有格式的
用def定义,可以自动推导当前的类型。对于Str2,它属于GString类了。可以在${}放入一个表达式,结果值会作为字符串的一部分内容。
String不能转化成GString,而GString可以转化成String。
对于String中的方法分为三类:
- java.lang.String
- DefaultGroovyMethods
- StringGroovyMethods
如:
str.reverse()反转
str.capitalize() 首字母大写
str[0] 获取一个字符
str[0..4] 截取第0个到第四个之间的字符串
str.eachLine {line->println(line)} 闭包获取每一行字符串
3、闭包
按照我的理解闭包就是一个代码块,这个代码块有点特殊,他可以像方法一样接受参数、执行并返回结果。
// 定义一个带有闭包参数的方法
String echo(Closure closure, int num1, int num2) {
closure.call(num1, num2)
}
// 调用闭包方法
String s1 = echo({ num1, num2 ->
"${num1}+${num2} = ${(num1 + num2)}"
}, 1, 2)
println(s1)
String s2 = echo({ num1, num2 ->
"${num1}-${num2} = ${(num1 - num2)}"
}, 1, 2)
println(s2)
// 结果:
// 1+2 = 3
// 1-2 = -1
上面的echo方法就是接收一个闭包参数,该闭包是接收两个参数,根据策略计算并返回结果。闭包的定义是采用Closure,可以用closure.call(num1, num2)执行闭包。执行echo方法时,一个传入的是计算加法的闭包,另一个是计算减法的闭包。这个就像策略一样,你负责传入策略我给你相应的结果。
调用方式:
- closure.call(num1, num2) : 采用call方法
- closure(num1, num2) : 以方法的形式
闭包的参数:
- 显示参数
闭包中显示的指明具体的参数。 - 隐士参数
groovy中使用隐士it代表传入的参数,有且只能由0个或一个参数才行。
def colusre = {
println("my name is ${it}")
}
colusre()
colusre("phj")
// 结果:
// my name is null
// my name is phj
对于第一个不传入参数的就是null,而且在闭包的声明中也没有指明是否有参数,而是使用了it代替。
闭包的返回值:
闭包都是有返回值的,在没有显示return返回的时候,最后一行就是返回的内容。如果最后一行是void形式,那么返回值就是null。
闭包使用:
int cal(int number) {
int result = 0
number.times({num->result+=num})
result
}
println(cal(10))
利用闭包实现从1加到9,结果等于45。
看下times源码:
public static void times(Number self, @ClosureParams(value = SimpleType.class,options = {"int"}) Closure closure) {
int i = 0;
for(int size = self.intValue(); i < size; ++i) {
closure.call(i);
if (closure.getDirective() == 1) {
break;
}
}
}
就是循环的调用闭包,在执行闭包的时候将之前的数据累加起来。
常见字符串闭包函数
- str.find(Closure closure) 查找满足条件的第一个数
- str.findAll(Closure closure) 查找所有满足条件的数
- str.any(Closure closure) 判断是不是有一个数满足闭包的要求的
- str.collect(Closure closure) 遍历返回转换后的字符List
闭包的变量
- this
- owner
- delegate
def colusre = {
println(this) : 代表闭包定义处的类
println(owner) : 代表闭包定义处的类或者对象
println(delegate) : 代表任意对象,默认是和owner一致
}
执行该闭包的结果是:com.phj.groovy为包名,T为类名,后面是T的对象。从结果来看这三个的打印都是一样,都代表了同一个对象。
com.phj.groovy.T@35e2d654
com.phj.groovy.T@35e2d654
com.phj.groovy.T@35e2d654
再如:
def colusre = {
def interColusre = {
println(this)
println(owner)
println(delegate)
}
interColusre()
println(this)
println(owner)
println(delegate)
}
它的执行结果就是:
com.phj.groovy.T@55183b20
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T@55183b20
com.phj.groovy.T@55183b20
com.phj.groovy.T@55183b20
因为interColusre 是定义在闭包里面,所以这里面的值就不是和this一致了,而是指代着外边运行的闭包对象。而delegate默认是和owner一样。
再者看下delegate:
def colusre = {
def interColusre = {
println(this)
println(owner)
delegate = this
println(delegate)
}
interColusre()
}
在内部的闭包interColusre将delegate指明为this。
结果:这样就修改了delegate对象了
com.phj.groovy.T@55183b20
com.phj.groovy.T$_run_closure4@7d8995e
com.phj.groovy.T@55183b20
闭包的委托策略:
即通过delegate来指向新的数据。
class Student {
def name
def pretty = {"my name is ${name}"}
String toString() {
pretty.call()
}
}
class Teacher {
def name
}
def student = new Student(name:"student")
def teacher = new Teacher(name:"teacher")
println(student.toString())
student.pretty.delegate = teacher
// 修改委托策略
student.pretty.resolveStrategy = Closure.DELEGATE_FIRST
println(student.toString())
结果:
my name is student
my name is teacher
定义两个类,两个类都有同样的属性,现在通过更改委托和委托策略将student中打印的name指向teacher中的name。
三、基本数据结构
1、List列表
定义方式:
- def list = new ArrayList() : java的定义方式
- def list = [1,2,3,] : groovy的定义方式
List中有很多子List,如ArrayList和LinkedList等。
List操作:
- add : list.add(1)
- remove :list.remove(1)
- 排序 :Collections.sort(list)
- 遍历 :list.forEach()
- 查找 : list.find()
2、Map字典
定义方式:
- def map = new HashMap() : java中定义的方法
- def map = [1:"first",2:"second"] : groovy中定义方式
Map操作:
- 增 :map[3] = 'third' 或者 map.put(3,'third')
- 删 :map.remove()
- 查 :map[1] 或者map.get()
- 排序 :map.sort()
- 遍历 :map.forEach()或者 map.each() 或者 map.eachWithIndex()
需要注意的是:Map中的value的类型不一定是固定的,可以是任意类型的。
3、Range范围
Range是List的一个子类
定义方式:
- def range = 1..10 代表1到10
操作:
- range.from : 开始值
- range.to : 结束值
- 查 :range[0]或者range.get()
- 遍历 :range.each()
四、面向对象
类定义:
class Student {
String name
}
def student = new Student(name:"name")
- 类中的方法和参数默认是public的
- 不用构造方法也可以调用有参构造方法
- 类中默认设置了getXXX方法获取属性
接口定义:
接口中不能有非public的方法
interface Action {
void eat()
}
trait定义:
trait有点像抽象类,里面可以有无结构体的抽象方法,也可以实现默认的方法。但得通过implements来实现。
trait DefaultAction {
abstract void eat()
void play() {
}
}
groovy运行机制
在java中调用方法正常的逻辑就是直接调用某一个方法,如果没有该方法,编译器就会报错,但是在groovy中却不一样,即使没有该方法也不一定会抛出异常。上图就是groovy中的运行机制。
例一:invokeMethod
class Student {
String name
@Override
Object invokeMethod(String s, Object o) {
println("s(${o})")
return null
}
}
重写了Student中的invokeMethod方法,s代表方法名,o代表参数
调用student中没有的方法
def student = new Student()
student.cry()
// 结果:
// s([])
结果没有抛出异常,而是走了invokeMethod方法。
例二:methodMissing
class Student {
String name
@Override
Object invokeMethod(String s, Object o) {
println("s(${o})")
return null
}
def methodMissing(String name, Object args) {
println("the method ${name} is missing")
}
}
在加入methodMissing方法后,就不会走invokeMethod方法,而是走了methodMissing方法。
例三:metaClass
通过metaClass可以动态的为一个类增加属性和方法
如:
- Student.metaClass.age = 24 : 注入属性
- Student.metaClass.cry = {"i am cry"} : 注入方法