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"

如下面的代码

//强定义类型
int x = 10
println x.class double y = 3.14
println y.class //弱类型定义
def a = 10
println a.class def b = 3.14
println b.class def name = "tom"
println name.class
输出如下 :
class java.lang.Integer
class java.lang.Double
class java.lang.Integer
class java.math.BigDecimal
class java.lang.String

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

3 Groovy中的String相关

1. 字符串的定义

第一种方式:使用单引号

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

第二种方式:三个单引号

//之间的内容包含格式,里面的内容是什么格式的,显示出来的就是什么格式的
def content = '''\
line one
line two
line three
println content'''
println content.class //输出
line one
line two
line three
class java.lang.String

第三种方式:使用双引号

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

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

public class GStringImpl extends GString {
private String[] strings;
....

4 GString的用法

4.1 GString特性

特性1 可以拼任意表达式

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

问:Groovy中扩展出了GString,也就是可扩展的字符串,那么Groovy中两种字符串类型,即:String,GString,使用过程中需要注意什么呢?如果一个方法中的参数是String,那么可不可以传GString 的呢?

答:没有一点关系,使用是对开发者透明的,完全不用管,可以互相使用。看下面一个函数,参数需要String,但是传的是GString,看看输出结果都是正常的,编译器也没有报错,所以这两种字符串是不用关心类型的,是可以随便用的

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

def num = "3 + 5 = ${3 + 5}" //后面可以跟任意表达式

//传的是GString类型的
def result = show(num)
println result //方法接收的是String类型的
String show(String message){
return message
} //输出
3 + 5 = 8 //由此可以知道,GString,String在开发过程中不用刻意关心类型

4.1 String常用方法

  • 普通的方法
  • 带闭包的方法 (后面讲闭包的时候讲)
  • -普通的方法

    1. center()
    2. padLeft,padRight
    3. 可以直接比较,如下
def str = 'groovy'
def str2 = "hello"
def str3 = 'hello'
println str > str2
println str == str2
println str2 == str3 //输出
false
false
true //也可以直接使用索引,如
println str[0]
//输出
g //可以传入一个范围,如
println str[0..1]
//输出
gr //减法,把str1中包含的str2减掉,如
def str1 = 'hello,world'
def str2 = 'hello'
println str1 - str2
println str1.minus(str2)
//输出
,world
,world //字符串反转
def str3 = 'hello'
println str3.reverse()
//输出
olleh //所有单词首字母大写
def str4 = 'hello world'
println str4.capitalize()
//输出
Hello world //判断是否是数字类型的字符串,如
def str5 = '234'
println str5.isNumber()
//输出
true //转化成数字,如
def str6 = '123'
println str6
//输出
123

5 Groovy中的逻辑控制

逻辑控制语句有三种

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

这些逻辑控制是和Java中的一样的,但是又扩展了一些功能

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

//switch语句
def x = 3.14
def result
switch (x){
case 'test':
result = 'test' //字符串
break
case [4,5,6,'test']: //列表
result = 'list'
break
case 3..11:
result = 'range' //范围
break
case Integer:
result = 'Integer' //类型
break
case BigDecimal:
result = 'BigDecimal'
break
default:
result = 'default'
break
} println result
//输出
BigDecimal

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

//1 对范围的for循环
def sum = 0
for (i in 0..3){
sum += i
}
println sum
//输出
6 //2 对List的循环
def sum = 0
for (i in [1,2,3,4,5,6,7,8,9]){
sum += i
}
println sum
//输出
45 //3 对Map的循环
def sum = 0
for (i in ['tom':1,'jim':2,'xiaoming':3]){
sum += i.value
println i.key
}
println sum
//输出
tom
jim
xiaoming
6

6 Groovy中的闭包

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

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

6.1 闭包的基础

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

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

6.1.2 闭包的参数:普通参数和隐式参数

闭包是可以传参数的,有点像Java中的lambda表达式,如下代码

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

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

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

6.1.3 闭包的返回值:总是有返回值的

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

//4 闭包的返回值,如果没有return,最后一句话就是返回值
def closer = {
"hello world"
} //返回值是"hello world"
def result = closer.call()
println result
//输出
hello world

6.2 闭包的使用

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

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

6.1.1 与基本类型的结合使用

//用来求指定number的阶乘
//求5的阶乘 1*2*3*4*5 = 120
int res = fab(5)
println res int fab(int number){
int result = 1
1.upto(number,{
num -> result *= num
}) return result
}

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

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

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

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

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

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

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

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

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

//求10以内的和
int res = fab3(10)
println res int fab3(int number){
int result = 0 //圆括号省略,直接跟一个闭包
number.times {
num -> result += num
} return result
} //输出
45

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

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

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

6.1.2 与String的结合使用

//each()方法的使用

String str = 'hello world'
//把每一个字符都传给闭包
str.each {
temp -> print temp
}
//输出
hello world
//find()方法的使用

String str = 'tom has 63 books and 3 apples'

//查找第一个是数字的字符,闭包必须返回一个boolean值
def result = str.find {
word -> word.isNumber()
} println result
//输出
6

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

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

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

String str = 'tom has 63 books and 3 apples'

//查找所有是数字的字符
def result = str.findAll {
word -> word.isNumber()
} println result
//输出
[6, 3, 3]
//any()方法的使用

String str = 'tom has 63 books and 3 apples'

//判断字符串中是否包含数字
def result = str.any {
temp -> temp.isNumber()
} println result
//输出
true

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

  public static boolean any(Object self, Closure closure) {
BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) { //只要闭包条件满足,就返回true,很简单吧
if (bcw.call(iter.next())) return true;
}
return false;
}
//every()的用法 

String str = 'tom has 63 books and 3 apples'

//判断字符串中是否全是数字
def result = str.every {
temp -> temp.isNumber()
} println result
//输出
false

every()方法的原理如下:

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

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

//collect()的使用

String str = 'hello world'

//将字符串转化成大写
def result = str.collect {
temp -> temp.toUpperCase()
} println result
//输出
[H, E, L, L, O, , W, O, R, L, D]

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

public static <T> List<T> collect(Object self, Closure<T> transform) {
//注意第二个参数,new了一个新的ArrayList()
return (List<T>) collect(self, new ArrayList<T>(), transform);
}

public static <T> Collection<T> collect(Object self, Collection<T> collector, Closure<? extends T> transform) {
for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); ) { //将闭包处理过的结果都添加到新的ArrayList中
collector.add(transform.call(iter.next()));
} //返回闭包处理过的结果
return collector;
}

6.1 闭包的进阶使用

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

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

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

def myScript = {
println "myScript this=" + this
println "myScript owner=" + owner
println "myScript delegate=" + delegate
} myScript.call()
//输出
myScript this=variable.closer@48e4374
myScript owner=variable.closer@48e4374
myScript delegate=variable.closer@48e4374

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

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

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

def myScript = {
println "myScript this=" + this
println "myScript owner=" + owner
println "myScript delegate=" + delegate def innerCloser = {
println "innerClouser this =" + this
println "innerClouser owner=" + owner
println "innerClouser delegate=" + delegate
} innerCloser.call()
} myScript.call()
//输出
myScript this=variable.closer@3d680b5a
myScript owner=variable.closer@3d680b5a
myScript delegate=variable.closer@3d680b5a
innerClouser this =variable.closer@3d680b5a
innerClouser owner=variable.closer$_run_closure1@3e92efc3
innerClouser delegate=variable.closer$_run_closure1@3e92efc3

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

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

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

//定义了一个内部类
class Person{ } Person p = new Person() def myScript = {
println "myScript this=" + this
println "myScript owner=" + owner
println "myScript delegate=" + delegate def innerCloser = {
println "innerClouser this =" + this
println "innerClouser owner=" + owner
println "innerClouser delegate=" + delegate
} innerCloser.delegate = p innerCloser.call()
} myScript.call()
//输出
myScript this=variable.closer@5a63f509
myScript owner=variable.closer@5a63f509
myScript delegate=variable.closer@5a63f509
innerClouser this =variable.closer@5a63f509
innerClouser owner=variable.closer$_run_closure1@13e39c73
innerClouser delegate=variable.Person@64cd705f

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

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

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


class Student{
String name //定义一个闭包
def showMe = {
return "my name is $name"
} @Override
String toString() {
return showMe();
}
} class Teacher {
String name } def stu = new Student(name : 'tom')
def tea = new Teacher(name : 'Mrs Li') //1 没有改变委托策略的情况下
println stu.toString() //2 改变闭包的委托策略
stu.showMe.delegate = tea
stu.showMe.resolveStrategy = Closure.DELEGATE_FIRST //把委托策略改成先从delegate中找name
println stu.toString()
//输出
my name is tom
my 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.1 Java的定义方式
def list = new ArrayList() //1.2 groovy中定义
def list2 = [] //定义一个空的列表
def list3 = [1,2,3,4] //定义一个非空的列表 println list2.class
println list3.class
//输出
class java.util.ArrayList
class java.util.ArrayList

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

//1.2 定义数组

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

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

//1.3 列表的排序
def list = [-7,5,-3,9,4,0]
list.sort() //直接一句话就排序了(默认从小到大)
println list //输出
[-7, -3, 0, 4, 5, 9]
//1.4 列表的排序
def list = [-7,5,-3,9,4,0] //按照绝对值从大到小排序,闭包中传入的是排序规则
list.sort {
a,b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? 1 : -1
} println list
//输出
[9, -7, 5, 4, -3, 0]
def stringList = ['a','abc','hello','groovy']

//1.5 按照字符串的长度大小排序
stringList.sort {
it -> return it.size()
} println stringList
//输出
[a, abc, hello, groovy]
//1.6 查找列表中的第一个偶数
def list = [-7,5,-3,9,4,0,6]
int result = list.find {
temp -> return temp % 2 == 0
} println result
//输出
4

//1.7 查找列表中所有小于0的数
def list = [-7,5,-3,9,4,0,6]
def result = list.findAll {
temp -> return temp < 0
} println result
//输出
[-7, -3]
//1.8 统计列表中偶数的个数
def list = [-7,5,-3,9,4,0,6] int number = list.count {
return it % 2 == 0
} println number
//输出
3

7.2 映射

//1.1 映射的定义
def persons = [tom:'北京',jim:'上海',wendy:'天津'] //1.2 映射的使用
println persons['tom']
println persons.get('jim')
println persons.wendy //1.3 添加元素
persons.xiaoming = '杭州'
println persons //1.4 groovy中,可以添加一个复杂的元素,比如添加一个map
persons.complex = [a:1,b:2]
println persons //输出
北京
上海
天津
[tom:北京, jim:上海, wendy:天津, xiaoming:杭州]
[tom:北京, jim:上海, wendy:天津, xiaoming:杭州, complex:[a:1, b:2]]

groovy中的map的常用操作

//1.5 对map的遍历
def students = ['tom':89,'jim':68,'wendy':56,'bob':92] students.each {
def student -> println "key is " + student.key + " value is " + student.value
} //输出
key is tom value is 89
key is jim value is 68
key is wendy value is 56
key is bob value is 92
//1.6 对map的遍历,带index
def students = ['tom':89,'jim':68,'wendy':56,'bob':92] students.eachWithIndex { def student, int index ->
println "key=${student.key} value=${student.value} index=${index}"
} //输出
key=tom value=89 index=0
key=jim value=68 index=1
key=wendy value=56 index=2
key=bob value=92 index=3
//1.7 直接对map的遍历
def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] students.each {
key, value -> println "key=${key},value=${value}"
} //输出
key=tom,value=89
key=jim,value=68
key=wendy,value=56
key=bob,value=92
//1.8 查询第一个及格的人
def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] def result = students.find {
student -> return student.value > 60
} println result
//输出
tom=89
//1.9 查询所有及格的人
def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] def result = students.findAll {
student -> return student.value > 60
} println result //输出
[tom:89, jim:68, bob:92]
//2.0 查询及格的人数

def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92]

def number = students.count {
student -> student.value > 60
} println number //输出
3
//2.1 查询所有及格的人的名字
def students = ['tom': 89, 'jim': 68, 'wendy': 56, 'bob': 92] def names = students.findAll {
student -> student.value > 60
}.collect {
return it.key
} println names //输出
[tom, jim, bob]

7.2 范围

范围的定义

//1.1 范围的定义
def range = 1..10 //1.2 范围的使用
println range[0] //第一个元素的值
println range.contains(7) //是否包含7
println range.from //范围的起始值
println range.to //范围的结束值 //输出
1
true
1
10

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

8 Groovy的面向对象

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

8.1 Groovy中的元编程

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

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

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

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

下面用代码来演示:如下

//先定义一个类,还是以刚才的类定义为例
class Person {
String name
int age def addYear(int age){
this.age += age
} @Override
String toString() {
return "name=${name} age=${age}"
}
}
def person = new Person(name:'tom',age:23)

//调用一个没有的方法
//会报 groovy.lang.MissingMethodException 异常
person.show() //输出
Caught: groovy.lang.MissingMethodException: No signature of method: variable.Person.show() is applicable for argument types: () values: []
//重写invokeMethod()方法

class Person {
String name
int age def addYear(int age){
this.age += age
} @Override
String toString() {
return "name=${name} age=${age}"
} //重写invokeMethod()方法,name是调用的方法的名字,args是调用方法传的参数,一个方法找不到的时候,调用它代替
@Override
Object invokeMethod(String name, Object args) {
println "the method is ${name},the param is ${args}"
}
} //在另一个文件中,调用下面的代码
def person = new Person(name:'tom',age:23) //调用一个没有的方法
person.show() //输出
the method is show,the param is []

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

//重写methodMissing()方法
class Person {
String name
int age def addYear(int age){
this.age += age
} @Override
String toString() {
return "name=${name} age=${age}"
} //重写invokeMethod()方法,name是调用的方法的名字,args是调用方法传的参数
//一个方法找不到的时候,调用它代替
@Override
Object invokeMethod(String name, Object args) {
println "the method is ${name},the param is ${args}"
} //这个方法的优先级要高于invokeMethod(),有了这个方法,将不会再调用invokeMethod()方法
def methodMissing(String name,Object args){
println "the method ${name} is missing"
}
}
//在另一个文件中,调用下面的代码
def person = new Person(name:'tom',age:23) //调用一个没有的方法
person.show() //输出
the method show is missing

8.2 Groovy中的MetaClass

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

//为类动态添加一个属性
Person.metaClass.sex = '男' def person = new Person(name:'tom',age:23)
println person.sex
//输出

//为类动态添加一个方法
Person.metaClass.showAge = {
-> println age
} def person = new Person(name:'tom',age:23)
person.showAge()
//输出
23
//为类动态添加一个静态方法
Person.metaClass.static.createPerson = {
name,age -> new Person(name:name,age:age)
} def person = Person.createPerson('wendy',44)
println person //输出
name=wendy age=44

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

到现在,Groovy就讲完了,Groovy的用法还需要较多的练习才能记得牢

为学习gradle打下坚实的基础。

Gradle系列之一 Groovy语法精讲的更多相关文章

  1. Gradle系列之Groovy基础篇

    原文发于微信公众号 jzman-blog,欢迎关注交流. 上一篇学习了 Gradle 的入门知识,Gradle 基于 Groovy,今天学习一下 Groovy 的基础知识,Groovy 是基于 JVM ...

  2. iOS开发——语法篇OC篇&高级语法精讲二

    Objective高级语法精讲二 Objective-C是基于C语言加入了面向对象特性和消息转发机制的动态语言,这意味着它不仅需要一个编译器,还需要Runtime系统来动态创建类和对象,进行消息发送和 ...

  3. iOS开发——语法篇OC篇&高级语法精讲

    高级语法精讲 一.NSSet.NSMutableSet集合的介绍 1)NSSet.NSMutableSet集合,元素是无序的,不能有重复的值. 2)用实例方法创建一个不可变集合对象 例如: //宏定义 ...

  4. SQL语法精讲(包括建库、建表、建视图、查询、增加、删除、)

    SQL语法精讲(包括建库.建表.建视图.查询.增加.删除.修改) SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELE ...

  5. Markdown 常用语法精讲

    - #### 标题 (`# 跟标题名称一定要留空格`)> > # 一级标题> ## 二级标题> ### 三级标题> #### 四级标题> ##### 五级标题> ...

  6. 【C++自我精讲】基础系列二 const

    [C++自我精讲]基础系列二 const 0 前言 分三部分:const用法.const和#define比较.const作用. 1 const用法 const常量:const可以用来定义常量,不可改变 ...

  7. 【C++自我精讲】基础系列四 static

    [C++自我精讲]基础系列四 static 0 前言 变量的存储类型:存储类型按变量的生存期划分,分动态存储方式和静态存储方式. 1)动态存储方式的变量,生存期为变量所在的作用域.即程序运行到此变量时 ...

  8. 【C++自我精讲】基础系列一 指针与引用

    [C++自我精讲]基础系列一 指针与引用   一 前言   指针.引用.指针与引用区别. 二 指针   变量:代码中常常通过定义变量来申请并命名存储空间,并通过变量的名字来使用这段存储空间. //变量 ...

  9. 【C++自我精讲】基础系列六 PIMPL模式

    [C++自我精讲]基础系列六 PIMPL模式 0 前言 很实用的一种基础模式. 1 PIMPL解释 PIMPL(Private Implementation 或 Pointer to Implemen ...

随机推荐

  1. Linux常用C函数-接口处理篇(网络通信函数)

    接口处理篇accept,bind,connect,endprotoent,endservent,getsockopt,htonl,htons,inet_addr,inet_aton,inet_ntoa ...

  2. 带您了解Oracle层次查询

    http://database.51cto.com/art/201010/231539.htm Oracle层次查询(connect by )是结构化查询中用到的,下面就为您介绍Oracle层次查询的 ...

  3. [原创]安装Ubuntu Server 14.04后

    安装后许多软件都没有,需要进行安装. 官方指南:https://help.ubuntu.com/lts/serverguide/index.html 1.修改网络配置文件 用ifconfig查看本地网 ...

  4. php 中函数获取可变参数的方法, 这个语法有点像 golang 语言中的

    原文呢:http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration.strict Onl ...

  5. 前端高频面试题 JavaScript篇

    以下问题都来自于互联网前端面经分享,回答为笔者通过查阅资料加上自身理解总结,不保证解答的准确性,有兴趣讨论的同学可以留言或者私信讨论. 1.JS的异步机制? 2.闭包如何实现? 3.原型链.继承? 4 ...

  6. c++引用和const 用法 数组 指针

    非const引用,只能用object为其赋值: <c++primer>P52 而const引用则可以用临时变量为其赋值: 如: const int &r = 32://可以 int ...

  7. 利用反射技术实现POJO的数据库操作

    记得第一次写项目的时候,傻傻的数据库一张表,代码里就写一个DAO类,几张表就写几个DAO类,大量的反复代码,自己粘着都嫌烦,后来接触了Hibernate,不得不说对我们这样的小白用处还是非常大的.那么 ...

  8. 【整理】nand相关

    记录nand相关知识.主要是mtd和ubi 什么是UBI 它是一种flash管理方式 flash是一系列连续的物理擦除块组成的. UBI卷是一系列连续的逻辑擦除块(eraseblock),每一块都能够 ...

  9. Multi-company rules

    Object Name Domain 说明 Point of Sale Point Of Sale Order [('company_id', '=', user.company_id.id)] 指派 ...

  10. HDU 4791 Alice&#39;s Print Service 水二分

    点击打开链接 Alice's Print Service Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ( ...