Gradle技术之一 Groovy语法精讲

Gradle技术之一 Groovy语法精讲

gradle脚本是基于groovy语言开发的,想要学好gradle必须先要对groovy有一个基本的认识

1. Groovy特点

  • groovy是一种DSL语言,所谓的DSL语言,就是专门针对某一特定领域的语言,专精而不专广
  • 是一种基于JVM的开发语言,也是编译成class字节码文件
  • 结合和Python,Ruby,PHP等语言的特性,写脚本非常强大
  • Groovy可以与Java完美结合,而且可以使用Java所有的类库
  • 语法上支持动态类型,闭包等新语言的特性
  • 支持面向过程和面向对象编程

2. Groovy语法精讲

1 变量的类型和定义

  • -变量的类型分两种
  1. 基本类型:和java的基本类型一样,int,long,double,float,boolean,byte,String等 注意Groovy中,这些基本类型实际上都会被系统装箱为对应的对象类型,比如int就会被自动装箱为Integer

  2. 对象类型:和Java的一样

  • - 变量的定义
  1. 强类型定义:如 int a=10 ,指定变量的类型
  2. 弱类型定义:如 def b = 5,系统根据后面的值自动判断b是什么类型
  • - Groovy语法小点
  1. 语句后面可以不带分号,也可以带分号,如定义一个变量 int a = 10
  2. 输出一句话,直接println就行了,圆括号也可以省略,如 println "hello,world"
  3. 定义变量或者函数可以使用关键字def ,也可以按照Java的语法格式定义,如def name="tom"

如下面的代码

1//强定义类型 2int x = 10 3println x.class 4 5double y = 3.14 6println y.class 7 8 9//弱类型定义 10def a = 10 11println a.class 12 13def b = 3.14 14println b.class 15 16def name = "tom" 17println name.class 18输出如下 : 19class java.lang.Integer 20class java.lang.Double 21class java.lang.Integer 22class java.math.BigDecimal 23class java.lang.String

注意:在Groovy中,所有定义的基本类型都会被系统自动装箱为相应的包装类型

3 Groovy中的String相关

1. 字符串的定义

第一种方式:使用单引号

1//使用单引号定义的字符串,里面的内容是不可以改变的 2//等价于 Java中的 String name = "hello world"; 3def name = 'hello world' 4println name 5println name.class 6 7//输出 8hello world 9class java.lang.String

第二种方式:三个单引号

1//之间的内容包含格式,里面的内容是什么格式的,显示出来的就是什么格式的 2def content = '''\ 3line one 4line two 5line three 6println content''' 7println content.class 8 9//输出 10line one 11line two 12line three 13class java.lang.String

第三种方式:使用双引号

1//上面两种方式定义的字符串是不可改变的,但是这种方式定义的字符是可以扩展的,里面可以包含其它的变量 2def name = "android" 3def str = "hello $name" 4println str 5println str.class 6 7//输出 8hello android 9class org.codehaus.groovy.runtime.GStringImpl

注意:第三种方式定义的字符串,里面带有 $ 符号拼接的字符类型就是GString类型,其它的都还是String类型,由此可知,Groovy已经扩展了我们的字符串,可源码可知org.codehaus.groovy.runtime.GStringImpl就是继承自GString,如下:

1public class GStringImpl extends GString { 2 private String[] strings; 3 .... 4

4 GString的用法

4.1 GString特性

特性1 可以拼任意表达式

1def num = "3 + 5 = ${3 + 5}" //后面可以跟任意表达式 2println num 3//输出 43 + 5 = 8

问:Groovy中扩展出了GString,也就是可扩展的字符串,那么Groovy中两种字符串类型,即:String,GString,使用过程中需要注意什么呢?如果一个方法中的参数是String,那么可不可以传GString 的呢? 答:没有一点关系,使用是对开发者透明的,完全不用管,可以互相使用。看下面一个函数,参数需要String,但是传的是GString,看看输出结果都是正常的,编译器也没有报错,所以这两种字符串是不用关心类型的,是可以随便用的

特性2 两种字符串类型可以互用

1def num = "3 + 5 = ${3 + 5}" //后面可以跟任意表达式 2 3//传的是GString类型的 4def result = show(num) 5println result 6 7 8//方法接收的是String类型的 9String show(String message){ 10 return message 11} 12 13//输出 143 + 5 = 8 15 16//由此可以知道,GString,String在开发过程中不用刻意关心类型 17

4.1 String常用方法

  • 普通的方法
  • 带闭包的方法 (后面讲闭包的时候讲)
  • -普通的方法
    1. center()
    2. padLeft,padRight
    3. 可以直接比较,如下
1def str = 'groovy' 2def str2 = "hello" 3def str3 = 'hello' 4println str > str2 5println str == str2 6println str2 == str3 7 8//输出 9false 10false 11true 12 13//也可以直接使用索引,如 14println str[0] 15//输出 16g 17 18 19//可以传入一个范围,如 20println str[0..1] 21//输出 22gr 23 24 25//减法,把str1中包含的str2减掉,如 26def str1 = 'hello,world' 27def str2 = 'hello' 28println str1 - str2 29println str1.minus(str2) 30//输出 31,world 32,world 33 34 35//字符串反转 36def str3 = 'hello' 37println str3.reverse() 38//输出 39olleh 40 41 42//所有单词首字母大写 43def str4 = 'hello world' 44println str4.capitalize() 45//输出 46Hello world 47 48 49//判断是否是数字类型的字符串,如 50def str5 = '234' 51println str5.isNumber() 52//输出 53true 54 55 56//转化成数字,如 57def str6 = '123' 58println str6 59//输出 60123 61 62

5 Groovy中的逻辑控制

逻辑控制语句有三种

  • 顺序控制:单步往下执行
  • 条件逻辑:if/else 和 switch/case
  • 循环逻辑:while 和 for

这些逻辑控制是和Java中的一样的,但是又扩展了一些功能 其中if/elsewhile和Java中的用法是一样的,switch/casefor增加了一些扩展,我们使用下面的代码来演示这两种扩展的用法,代码如下:

1//switch语句 2def x = 3.14 3def result 4switch (x){ 5 case 'test': 6 result = 'test' //字符串 7 break 8 case [4,5,6,'test']: //列表 9 result = 'list' 10 break 11 case 3..11: 12 result = 'range' //范围 13 break 14 case Integer: 15 result = 'Integer' //类型 16 break 17 case BigDecimal: 18 result = 'BigDecimal' 19 break 20 default: 21 result = 'default' 22 break 23} 24 25println result 26//输出 27BigDecimal 28

Groovy中的switch中可以是任何类型,数据

1//1 对范围的for循环 2def sum = 0 3for (i in 0..3){ 4 sum += i 5} 6println sum 7//输出 86 9 10 11//2 对List的循环 12def sum = 0 13for (i in [1,2,3,4,5,6,7,8,9]){ 14 sum += i 15} 16println sum 17//输出 1845 19 20//3 对Map的循环 21def sum = 0 22for (i in ['tom':1,'jim':2,'xiaoming':3]){ 23 sum += i.value 24 println i.key 25} 26println sum 27//输出 28tom 29jim 30xiaoming 316 32

6 Groovy中的闭包

Groovy中的闭包很强大,下面主要从三个方向讲解闭包

  • 1 闭包的基础详解
  • 2 闭包的使用详解
  • 3 闭包的进阶详解

6.1 闭包的基础

6.1.1 闭包的概念:闭包就是一段代码块,可以命名可以被调用,使用和方法类似

1//1 定义一个闭包,闭包的定义就是这么简单 2// 就是一段代码块,可以命名,可以被调用 3def closer = { 4 println "hello groovy" 5} 6 7//2 闭包的两种调用方式 8// 建议使用第一种方式调用,这样不会和方法的调用混淆 9closer.call() 10closer() 11//输出 12hello groovy 13hello groovy

6.1.2 闭包的参数:普通参数和隐式参数 闭包是可以传参数的,有点像Java中的lambda表达式,如下代码

1//1 定义一个无参的闭包 2// -> 也可以省略, -> 前面的是参数,-> 后面的是闭包体 3def closer = { 4 -> println "hello groovy" 5} 6 7//使用 8closer.call() 9closer() 10
1//2 定义一个有参的闭包, 参数是name 2def closer = { 3 String name -> println "hello $name" 4} 5 6closer.call() //参数可以不传,不传就是null 7closer.call('world') 8closer('android')

闭包还有一个隐式的参数 it ,类似类中的this,如果定义闭包没有明确指定参数,但是调用了闭包传了参数,那么就可以在代码中使用 it 关键字,如下

1//3 定义一个无参的闭包, 使用隐式的参数关键字 it 2def closer = { 3 println "hello $it" 4} 5 6closer.call() //参数可以不传,不传就是null 7closer.call('world') 8closer('android') 9

6.1.3 闭包的返回值:总是有返回值的 闭包总是有返回值的,如果没有明确的return,返回值就决定在最后一句代码,如下

1//4 闭包的返回值,如果没有return,最后一句话就是返回值 2def closer = { 3 "hello world" 4} 5 6//返回值是"hello world" 7def result = closer.call() 8println result 9//输出 10hello world 11

6.2 闭包的使用

闭包的使用主要从以下几个方面讲

  • 1 与基本类型的结合使用
  • 2 与String结合使用
  • 3 与数据结构结合使用
  • 4 与文件等结合使用

6.1.1 与基本类型的结合使用

1//用来求指定number的阶乘 2//求5的阶乘 1*2*3*4*5 = 120 3int res = fab(5) 4println res 5 6int fab(int number){ 7 int result = 1 8 1.upto(number,{ 9 num -> result *= num 10 }) 11 12 return result 13} 14

这段代码是不是很简洁,主要的应该都在upto()方法中,我们来看一下upto()方法的源码,如下

1 public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) { 2 int self1 = self.intValue(); //初始值,就是1 3 int to1 = to.intValue(); //结束值,就是5 4 if (self1 <= to1) {//如果初始值小于结束值,就循环 5 //开始从 self1到to1的循环,把每一个值都交给最后一个闭包来处理 6 //而在我们的闭包中,又把每一项乘的结果保存在了result变量中 7 for (int i = self1; i <= to1; i++) { 8 closure.call(i); 9 } 10 } else 11 throw new GroovyRuntimeException("The argument (" + to + 12 ") to upto() cannot be less than the value (" + self + ") it's called on."); 13 }

注意,Groovy方法中,如果最后一个参数是闭包,那么圆括号是可以省略的,我们用downto()方法来演示省略圆括号的用法

既然有upto()方法,那么肯定也有downto()方法了,我们来看一下downto()方法的使用,

最后一个参数是闭包的话,方法的圆括号可以省略

1//求5的阶乘 1*2*3*4*5 = 120 2int res = fab2(5) 3println res 4 5//注意,最后一个参数是闭包的话,方法的圆括号可以省略 6int fab2(int number){ 7 int result = 1 8 number.downto(1){ 9 num -> result *= num 10 } 11 12 return result 13}

同样,downto()的源码如下:

1//与upto()源码类似 2 public static void downto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) { 3 int self1 = self.intValue(); //初始值是5 4 int to1 = to.intValue(); //结束值是1 5 if (self1 >= to1) { 6 for (int i = self1; i >= to1; i--) { 7 closure.call(i); 8 } 9 } else 10 throw new GroovyRuntimeException("The argument (" + to + 11 ") to downto() cannot be greater than the value (" + self + ") it's called on."); 12 }

再看一个例子,方法只有一个闭包参数的,如下,求和

1//求10以内的和 2int res = fab3(10) 3println res 4 5int fab3(int number){ 6 int result = 0 7 8 //圆括号省略,直接跟一个闭包 9 number.times { 10 num -> result += num 11 } 12 13 return result 14} 15 16//输出 1745 18

同样,times()方法的源码如下:

1 public static void times(Number self, @ClosureParams(value=SimpleType.class,options="int") Closure closure) { 2 for (int i = 0, size = self.intValue(); i < size; i++) { 3 closure.call(i); 4 if (closure.getDirective() == Closure.DONE) { 5 break; 6 } 7 } 8 }

从上面几个例子可以知道,我们在写闭包的时候,有时候并不知道需要传入什么样的参数,这个时候就只能去查看源码或者官方文档了,所以查看源码和官方文档是一个比较好的习惯

6.1.2 与String的结合使用

1//each()方法的使用 2 3String str = 'hello world' 4//把每一个字符都传给闭包 5str.each { 6 temp -> print temp 7} 8//输出 9hello world 10
1//find()方法的使用 2 3String str = 'tom has 63 books and 3 apples' 4 5//查找第一个是数字的字符,闭包必须返回一个boolean值 6def result = str.find { 7 word -> word.isNumber() 8} 9 10println result 11//输出 126

可以看下find()函数是如何工作的,find()的源码如下 :

1 public static Object find(Object self, Closure closure) { 2 //把闭包包装成了一个BooleanClosureWrapper对象 3 BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure); 4 5 //遍历字符串,并把遍历的每一个字符串都交给闭包处理 6 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) { 7 Object value = iter.next(); 8 9 //如果闭包返回true,说明符合条件,就把value返回 10 if (bcw.call(value)) { 11 return value; 12 } 13 } 14 return null; 15 } 16

同理还有findAll()方法,用法如下

1String str = 'tom has 63 books and 3 apples' 2 3//查找所有是数字的字符 4def result = str.findAll { 5 word -> word.isNumber() 6} 7 8println result 9//输出 10[6, 3, 3]
1//any()方法的使用 2 3String str = 'tom has 63 books and 3 apples' 4 5//判断字符串中是否包含数字 6def result = str.any { 7 temp -> temp.isNumber() 8} 9 10println result 11//输出 12true 13

any()方法的工作原理如下:

1 public static boolean any(Object self, Closure closure) { 2 BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure); 3 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) { 4 5 //只要闭包条件满足,就返回true,很简单吧 6 if (bcw.call(iter.next())) return true; 7 } 8 return false; 9 }
1//every()的用法 2 3String str = 'tom has 63 books and 3 apples' 4 5//判断字符串中是否全是数字 6def result = str.every { 7 temp -> temp.isNumber() 8} 9 10println result 11//输出 12false 13

every()方法的原理如下:

1 public static boolean every(Object self, Closure closure) { 2 BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure); 3 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) { 4 5 //只要有一项不满足,立马返回 6 if (!bcw.call(iter.next())) { 7 return false; 8 } 9 } 10 return true; 11 }

any()方法是只要有一项满足就返回, every()方法是只要有一项不满足就返回,正好相反

1//collect()的使用 2 3String str = 'hello world' 4 5//将字符串转化成大写 6def result = str.collect { 7 temp -> temp.toUpperCase() 8} 9 10println result 11//输出 12[H, E, L, L, O, , W, O, R, L, D]

collect()方法的工作原理如下:

1public static <T> List<T> collect(Object self, Closure<T> transform) { 2 //注意第二个参数,new了一个新的ArrayList() 3 return (List<T>) collect(self, new ArrayList<T>(), transform); 4 }
1 2 public static <T> Collection<T> collect(Object self, Collection<T> collector, Closure<? extends T> transform) { 3 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); ) { 4 5 //将闭包处理过的结果都添加到新的ArrayList中 6 collector.add(transform.call(iter.next())); 7 } 8 9 //返回闭包处理过的结果 10 return collector; 11 }

6.1 闭包的进阶使用

  • 1 闭包的关键字变量 this, owner, delegate
  • 2 闭包的委托策略

6.1.1 闭包的三个关键字 this, owner, delegate

首先先打印出这三个变量,看看输出什么

1def myScript = { 2 println "myScript this=" + this 3 println "myScript owner=" + owner 4 println "myScript delegate=" + delegate 5} 6 7myScript.call() 8//输出 9myScript this=variable.closer@48e4374 10myScript owner=variable.closer@48e4374 11myScript delegate=variable.closer@48e4374

可以看到,这三个代表的是一个意思,那么这三个关键字到底有什么区别呢?

  • 1 this :代表闭包定义处的类
  • 2 owner :代表闭包定义处的类或者对象
  • 3 delegate:代表任意对象,但是默认是和owner是一样的

如果在闭包中再定义一个闭包呢,看看这三个关键字会打印出什么

1def myScript = { 2 println "myScript this=" + this 3 println "myScript owner=" + owner 4 println "myScript delegate=" + delegate 5 6 def innerCloser = { 7 println "innerClouser this =" + this 8 println "innerClouser owner=" + owner 9 println "innerClouser delegate=" + delegate 10 } 11 12 innerCloser.call() 13} 14 15 16myScript.call() 17//输出 18myScript this=variable.closer@3d680b5a 19myScript owner=variable.closer@3d680b5a 20myScript delegate=variable.closer@3d680b5a 21innerClouser this =variable.closer@3d680b5a 22innerClouser owner=variable.closer$_run_closure1@3e92efc3 23innerClouser delegate=variable.closer$_run_closure1@3e92efc3 24

所以,总结下来,只有三句话:

  • 1 this,owner,delegate这三个关键字在类和方法中定义时,指向是一样的
  • 2 在闭包中定义的闭包的时候,ownerdelegate指向的是外面的闭包对象
  • 3 在修改了delegate的时候指向的时候,delegate又和其它两个不一样了

如下代码,修改了delegate的指向

1//定义了一个内部类 2class Person{ 3 4} 5 6Person p = new Person() 7 8def myScript = { 9 println "myScript this=" + this 10 println "myScript owner=" + owner 11 println "myScript delegate=" + delegate 12 13 def innerCloser = { 14 println "innerClouser this =" + this 15 println "innerClouser owner=" + owner 16 println "innerClouser delegate=" + delegate 17 } 18 19 innerCloser.delegate = p 20 21 innerCloser.call() 22} 23 24 25myScript.call() 26//输出 27myScript this=variable.closer@5a63f509 28myScript owner=variable.closer@5a63f509 29myScript delegate=variable.closer@5a63f509 30innerClouser this =variable.closer@5a63f509 31innerClouser owner=variable.closer$_run_closure1@13e39c73 32innerClouser delegate=variable.Person@64cd705f 33

可以看到delegate指向了Person,不再和owner一样了

6.1.2 this, owner, delegate的作用,也就是委托策略

用一段代码来演示更改委托策略,代码如下:

1 2class Student{ 3 String name 4 5 //定义一个闭包 6 def showMe = { 7 return "my name is $name" 8 } 9 10 @Override 11 String toString() { 12 return showMe(); 13 } 14} 15 16class Teacher { 17 String name 18 19} 20 21def stu = new Student(name : 'tom') 22def tea = new Teacher(name : 'Mrs Li') 23 24//1 没有改变委托策略的情况下 25println stu.toString() 26 27 28//2 改变闭包的委托策略 29stu.showMe.delegate = tea 30stu.showMe.resolveStrategy = Closure.DELEGATE_FIRST //把委托策略改成先从delegate中找name 31println stu.toString() 32//输出 33my name is tom 34my name is Mrs Li

可以看到,在不改变委托策略的情况下,输出的是my name is tom

在改变了委托策略下,把闭包的指向改成了 tea,并且把委托策略也改成了Closure.DELEGATE_FIRST ,那么查找name的时候,首先就从deleage指向处查找 所以打印的是my name is Mrs Li

7 Groovy的数据结构

Groovy中主要有3种常用的数据结构。列表,映射,范围 这三个数据结构比较简单,主要以代码的形式来讲,如下

7.1 列表

1//1 定义列表 2 3//1.1 Java的定义方式 4def list = new ArrayList() 5 6//1.2 groovy中定义 7def list2 = [] //定义一个空的列表 8def list3 = [1,2,3,4] //定义一个非空的列表 9 10println list2.class 11println list3.class 12//输出 13class java.util.ArrayList 14class java.util.ArrayList

可以看到,直接这样定义的就是一个ArrayList

1//1.2 定义数组 2 3//在groovy中使用as关键字定义数组,注意和列表的区别 4def array = [1,2,3,4] as int[] 5 6//或者使用强类型的定义方式 7int[] array2 = [1,2,3] 8

由于在Groovy中,列表和数组的定义方式类似,使用也相似,一般我们只使用列表就够了

1//1.3 列表的排序 2def list = [-7,5,-3,9,4,0] 3list.sort() //直接一句话就排序了(默认从小到大) 4println list 5 6//输出 7[-7, -3, 0, 4, 5, 9] 8
1//1.4 列表的排序 2def list = [-7,5,-3,9,4,0] 3 4//按照绝对值从大到小排序,闭包中传入的是排序规则 5list.sort { 6 a,b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? 1 : -1 7} 8 9println list 10//输出 11[9, -7, 5, 4, -3, 0]
1def stringList = ['a','abc','hello','groovy'] 2 3//1.5 按照字符串的长度大小排序 4stringList.sort { 5 it -> return it.size() 6} 7 8println stringList 9//输出 10[a, abc, hello, groovy]
1//1.6 查找列表中的第一个偶数 2def list = [-7,5,-3,9,4,0,6] 3int result = list.find { 4 temp -> return temp % 2 == 0 5} 6 7println result 8//输出 94
1 2//1.7 查找列表中所有小于0的数 3def list = [-7,5,-3,9,4,0,6] 4def result = list.findAll { 5 temp -> return temp < 0 6} 7 8println result 9//输出 10[-7, -3]
1//1.8 统计列表中偶数的个数 2def list = [-7,5,-3,9,4,0,6] 3 4int number = list.count { 5 return it % 2 == 0 6} 7 8println number 9//输出 103

7.2 映射

1//1.1 映射的定义 2def persons = [tom:'北京',jim:'上海',wendy:'天津'] 3 4//1.2 映射的使用 5println persons['tom'] 6println persons.get('jim') 7println persons.wendy 8 9//1.3 添加元素 10persons.xiaoming = '杭州' 11println persons 12 13//1.4 groovy中,可以添加一个复杂的元素,比如添加一个map 14persons.complex = [a:1,b:2] 15println persons 16 17//输出 18北京 19上海 20天津 21[tom:北京, jim:上海, wendy:天津, xiaoming:杭州] 22[tom:北京, jim:上海, wendy:天津, xiaoming:杭州, complex:[a:1, b:2]]

groovy中的map的常用操作

1//1.5 对map的遍历 2def students = ['tom':89,'jim':68,'wendy':56,'bob':92] 3 4students.each { 5 def student -> println "key is " + student.key + " value is " + student.value 6} 7 8//输出 9key is tom value is 89 10key is jim value is 68 11key is wendy value is 56 12key is bob value is 92 13
1//1.6 对map的遍历,带index 2def students = ['tom':89,'jim':68,'wendy':56,'bob':92] 3 4students.eachWithIndex { def student, int index -> 5 println "key=${student.key} value=${student.value} index=${index}" 6} 7 8//输出 9key=tom value=89 index=0 10key=jim value=68 index=1 11key=wendy value=56 index=2 12key=bob value=92 index=3
1//1.7 直接对map的遍历 2def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] 3 4students.each { 5 key, value -> println "key=${key},value=${value}" 6} 7 8//输出 9key=tom,value=89 10key=jim,value=68 11key=wendy,value=56 12key=bob,value=92
1//1.8 查询第一个及格的人 2def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] 3 4 5def result = students.find { 6 student -> return student.value > 60 7} 8 9println result 10//输出 11tom=89
1//1.9 查询所有及格的人 2def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] 3 4def result = students.findAll { 5 student -> return student.value > 60 6} 7 8println result 9 10//输出 11[tom:89, jim:68, bob:92]
1//2.0 查询及格的人数 2 3def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] 4 5def number = students.count { 6 student -> student.value > 60 7} 8 9println number 10 11//输出 123
1//2.1 查询所有及格的人的名字 2def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] 3 4def names = students.findAll { 5 student -> student.value > 60 6}.collect { 7 return it.key 8} 9 10println names 11 12//输出 13[tom, jim, bob]

7.2 范围

范围的定义

1//1.1 范围的定义 2def range = 1..10 3 4//1.2 范围的使用 5println range[0] //第一个元素的值 6println range.contains(7) //是否包含7 7println range.from //范围的起始值 8println range.to //范围的结束值 9 10//输出 111 12true 131 1410

范围就是这么简单,轻量级的list

8 Groovy的面向对象

  • 1 Groovy中类的方法,变量,默认的都是public
  • 2 接口和Java中的几乎一样,只有一点区别,就是只能定义public的方法,不能用protected
1//1.1 类的定义 2class Person { 3 String name 4 int age 5 6 //方法的定义 7 def addYear(int age){ 8 this.age += age 9 } 10 11 @Override 12 String toString() { 13 return "name=${name} age=${age}" 14 } 15} 16
1//1.2 实例化一个类的对象 2def person = new Person() 3def person1 = new Person(name:'tom',age:23) 4def person2 = new Person(name:'tom') 5 6println person.toString() 7println person1.toString() 8println person2.toString() 9 10//输出 11name=null age=0 12name=tom age=23 13name=tom age=0 14
1//1.3 get/set方法 2//无论是直接用 . 还是调用get/set方法,最终都是调用的get/set方法 3//这是和Java不一样的地方,是编译器自动为我们生成的get/set 4def person = new Person(name:'tom',age:23) 5 6println "name=${person.name} , age=${person.age}" 7println "name=${person.getName()}, age=${person.getAge()}" 8 9//输出 10name=tom , age=23 11name=tom, age=23 12

8.1 Groovy中的元编程

元编程就是代码在执行过程中运行的时期,Groovy中,调用类的一个方法,如下 :

  • 1 类中是否有此方法,有则调用,如果没有
  • 2 从 MetaClass中查找是否有此方法,有则调用MetaClass中的方法,如果没有
  • 3 是否重写了methodMissing()方法,有则调用methodMissing()方法,如果没有
  • 4 是否重写了invokeMethod()方法,有则invokeMethod()方法,如果没有,throw MissingMethodException

主要是: 类 --> MetaClass --> methodMissing() --> invokeMethod()

java中如果类中没有这个方法,就直接报错了,但是Groovy中,运行时是非常强大的

下面用代码来演示:如下

1//先定义一个类,还是以刚才的类定义为例 2class Person { 3 String name 4 int age 5 6 def addYear(int age){ 7 this.age += age 8 } 9 10 @Override 11 String toString() { 12 return "name=${name} age=${age}" 13 } 14} 15 16
1def person = new Person(name:'tom',age:23) 2 3//调用一个没有的方法 4//会报 groovy.lang.MissingMethodException 异常 5person.show() 6 7//输出 8Caught: groovy.lang.MissingMethodException: No signature of method: variable.Person.show() is applicable for argument types: () values: [] 9
1//重写invokeMethod()方法 2 3class Person { 4 String name 5 int age 6 7 def addYear(int age){ 8 this.age += age 9 } 10 11 @Override 12 String toString() { 13 return "name=${name} age=${age}" 14 } 15 16 //重写invokeMethod()方法,name是调用的方法的名字,args是调用方法传的参数,一个方法找不到的时候,调用它代替 17 @Override 18 Object invokeMethod(String name, Object args) { 19 println "the method is ${name},the param is ${args}" 20 } 21} 22 23//在另一个文件中,调用下面的代码 24def person = new Person(name:'tom',age:23) 25 26//调用一个没有的方法 27person.show() 28 29//输出 30the method is show,the param is [] 31

所以,由此可知,如果类中没有方法,但是重写了invokeMethod()方法,groovy是不会报错的,会调用invokeMethod()方法,可以在这里面进行提示开发者,没有这个方法

1//重写methodMissing()方法 2class Person { 3 String name 4 int age 5 6 def addYear(int age){ 7 this.age += age 8 } 9 10 @Override 11 String toString() { 12 return "name=${name} age=${age}" 13 } 14 15 //重写invokeMethod()方法,name是调用的方法的名字,args是调用方法传的参数 16 //一个方法找不到的时候,调用它代替 17 @Override 18 Object invokeMethod(String name, Object args) { 19 println "the method is ${name},the param is ${args}" 20 } 21 22 //这个方法的优先级要高于invokeMethod(),有了这个方法,将不会再调用invokeMethod()方法 23 def methodMissing(String name,Object args){ 24 println "the method ${name} is missing" 25 } 26}
1//在另一个文件中,调用下面的代码 2def person = new Person(name:'tom',age:23) 3 4//调用一个没有的方法 5person.show() 6 7//输出 8the method show is missing

8.2 Groovy中的MetaClass

MetaClass可以在运行时为类动态添加属性

1//为类动态添加一个属性 2Person.metaClass.sex = '男' 3 4def person = new Person(name:'tom',age:23) 5println person.sex 6//输出 7
1//为类动态添加一个方法 2Person.metaClass.showAge = { 3 -> println age 4} 5 6def person = new Person(name:'tom',age:23) 7person.showAge() 8//输出 923
1//为类动态添加一个静态方法 2Person.metaClass.static.createPerson = { 3 name,age -> new Person(name:name,age:age) 4} 5 6def person = Person.createPerson('wendy',44) 7println person 8 9//输出 10name=wendy age=44

Groovy这种动态给类添加属性和方法的特性可以不用通过重写类而添加类的功能

到现在,Groovy就讲完了,Groovy的用法还需要较多的练习才能记得牢 为学习gradle打下坚实的基础。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Gradle的安装与配置及Spring源码导入(亲测)

前言我这边使用的gradle版本是:gradle6.5.1idea版本是:ideaIU2019.3.1jdk:1.8Gradle简介Gradle是源于ApacheAnt和ApacheMaven概念的项目自动化构建开源工具,它使用一种基于Groovy的的特定领域语言(