Groovy 安装
在 Windows 下安装 Groovy
进入 groovy.apache.org/download.ht...

点击Download 4.0.27
按钮,开始下载,下载完成后解压apache-groovy-sdk-4.0.27.zip
,解压后,将groovy-4.0.27
移动到自己想放的目录
配置环境变量
打开 Windows 下的环境变量,新建一个名为GROOVY_HOME
的环境变量,变量的值就是 Groovy sdk 的目录,我这里存放的D:\develop
,如下图:


选中 Path 变量进行编辑


完成后点击"确定"
打开 windows 的命令行窗口,输入
sh
groovy -v
如果出现以下版本信息,则安装成功。

运行 Groovy
使用 Groovy 控制台运行
完成安装后,在 bin 目录下有一个GroovyConsole.bat
文件,双击打开,可以在里面编写并执行 Groovy 程序。

windows 系统用户按
Ctrl + Enter
或Ctrl + R
执行代码
在 Intellij Idea 中运行
我使用的 idea 版本是 2022.3.3,每个版本的 idea 界面不同
打开 idea 界面中点击 New Project,填写项目名,Language 选择 Groovy, Groovy SDK 选择刚安装的版本(idea 有内置的一些版本),完成后点击 Create。


点击 Tools 菜单下的Groovy Console
,并开始编写程序

编写完成后,点击绿色三角形开始运行,运行结果回在下方的控制台显示

Groovy 和 Java 的关系
我们先从一个 Java 代码编写的例子开始,同时它也是 Groovy 代码, 保存在一个后缀为 groovy 的文件中
java
public class GrvTest01 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("ho");
}
System.out.println("Hello Groovy");
}
}
在 windows 命令执行这段程序

可以看到,Java 编写的代码在 Groovy 中可以正常运行,实际上只保留 for 循环和输出与,其他都可以必要,依然可以正常运行,例如:
java
for (int i = 0; i < 10; i++) {
System.out.println("ho");
}
System.out.println("Hello Groovy");
把它保存为 GrvTest02.groovy,执行 groovy 运行

可以看到,运行结果与前面的完全一样,但代码要简洁的多。甚值可以更进一步,可以简化成下面的代码,效果也是一样的
groovy
for (i in 1..10) {println 'ho'}
println 'Hello Groovy'
把它保存为 GrvTest03.groovy,执行 groovy 运行

结果和前面的一致,而且代码更轻便了
GDK 介绍
Groovy 虽然支持 Java 的语法,但它并没有强迫我们学习新的类和库,而是通过向 JDK 中各种类添加方法,所以说 Groovy 扩展了 JDK, 这些扩展称之为 GDK(Groovy JDK)
Java 中可以使用 java.lang.process 与系统级进程进行交互,例如,我们在代码中调用 git help 命令并把 help 的内容打印出来,用 Java 的实现代码如下:
java
public class ExecuteProcess {
public static void main(String[] args) throws IOException {
Process process = Runtime.getRuntime().exec("git help");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
Groovy 通过在 java.lang.String 类上添加一个 execute() 方法,使一切变得简单。
groovy
println "git help".execute().text
运行输出的结果与上面的一模一样。

Groovy 数据类型
Groovy 的保留字
abstract | assert | break | case |
---|---|---|---|
catch | class | const | continue |
def | default | do | else |
enum | extends | final | finally |
for | goto | if | implements |
import | instanceof | intarface | native |
new | null | non-sealed | package |
public | protected | private | return |
static | strictfp | super | switch |
synchronized | this | thredsafe | throw |
throws | transient | try | while |
一般来说这些保留字不能用于定义变量、方法。如果用双引号引起来,也可以作为方法名,但不推荐这么做。例如:
groovy
def "abstract"() { true }
标识符
Groovy 标识符以字母、美元符号或下划线开头,不能以数字开头。
下面是合法的标识符:
groovy
def name
def item3
def with_me
def $dollarStart
下面是非法的标识符:
groovy
def 3tier
def a+b
def a#b
字符串
Groovy 允许实例化java.lang.String
类来定义一个字符串对象,同样也可以通过实例化groovy.lang.GString
类来定义一个字符串对象,两者可以混合使用。
例如,用单引号的字符串
groovy
'a single-quoted string'
三个单引号引起来的字符串
groovy
'''a triple-single-quoted string'''
groovy
def aMultilineString = '''line on
line two
line three ''' // ''' 定义的字符串可以换行,无需连接或转义字符
说明:用单引号或三个单引号定义的字符串不支持混合编程
双引号引起来的字符串
Groovy
"a duble-quoted string"
在 Groovy 中使用 ${} 作为占位符,占位符里面代表一个表达式的值,例如:
groovy
def name = "Groovy"
def greeting = "hello ${name}"
assert greeting.toString() == "Hello Groovy"
三个双引号引起来的字符串
用 """ 引起来的字符串行为是和双引号引起来的字符串是一样的,不同之处在于代表多行字符串,就像三个单引号定义的字符串,例如:
groovy
def name = 'Groovy'
def template = """
Dear Mr ${name},
You're the winner of the lottery!
Yours sincerly,
Dave
"""
Groovy 字符串总结
字符串名称 | 语法 | 是否可以混用 | 是否多行 | 转义字符 |
---|---|---|---|---|
单引号的 | '...' |
\ |
||
三个单引号的 | '''...''' |
是 | \ |
|
双引号的 | "..." |
是 | \ |
|
三个双引号的 | """...""" |
是 | 是 | \ |
斜线的 | /.../ |
是 | 是 | \ |
数值类型
Groovy 的数值型包括整数型(Integer)和小数型(decimal)两种
整型包括以下几种:
- byte
- char
- short
- int
- lang
- java.math.BigInteger
整数型
groovy
// 基本类型
byte b = 1
char c = 2
short s = 3
int i = 4
long l = 5
// 无线精度型
BigInteger bi = 6
使用 def 关键字定义数值型变量
groovy
def a = 1
assert a instanceof Integer
// 定义整型最大值 Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer
// 定义整形最大值 + 1,Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long
// 定义long 最大值,Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long
// 定义long最大值 + 1,Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger
定义二进制数,以0b
为前缀
groovy
// 整型
int xInt = 0b10101111
assert xInt == 175
// 短整型
short xShort = 0b11001001
assert xShort == 201
// 字节型
byte xByte = 0b11
assert xByte == 3
// long
long xLong = 0b101101101101
assert xLong == 2925L
// BigInteger
BigInteger xBigInteger = 0b111100100001
assert xBigInteger == 3873g
// 负整数
int xNegativeInt = -0b10101111
assert xNegativeInt == -175
定义八进制数,以0
开头
groovy
// 整型
int xInt = 077
assert xInt == 63
// 短整型
short xShort = 011
assert xShort == 9
// 字节型
byte xByte = 032
assert xByte == 26
// long
long xLong = 0246
assert xLong == 166l
// BigInteger
BigInteger xBigInteger = 01111
assert xBigInteger == 585g
// 负整数
int xNegativeInt = -077
assert xNegativeInt == -63
定义16进制数,以0x
为前缀
groovy
// 整型
int xInt = 0x77
assert xInt == 119
// 短整型
short xShort = 0xaa
assert xShort == 170
// 字节型
byte xByte = 0x3a
assert xByte == 58
// long
long xLong = 0xffff
assert xLong == 65535l
// BigInteger
BigInteger xBigInteger = 0xaaaa
assert xBigInteger == 43690g
// 负整数
int xNegativeInt = -0x77
assert xNegativeInt == -119
小数型(decimal)
以下定义的变量都属于小数型
groovy
// 基本类型
float f = 1.234
double d = 2.234
// 带有精度的小数类型
BigDecimal bd = 3.456
可以使用科学计数法表示相应类型的数值,例如:
groovy
assert 1e3 == 1_000.0
assert 2E4 == 20_000.0
assert 3e+1 == 30.0
assert 4E-2 == 0.04
assert 5e-1 == 0.5
Groovy 支持用下货先对数字进行分割,使数字更容易识别
groovy
long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
各种类型数值的后缀
类型 | 后缀 |
---|---|
BigInteger | G or g |
Long | L or l |
Integer | I or i |
BigDecimal | G or g |
Double | D or d |
Float | F or f |
例如:
groovy
assert 42I == Integer.valueOf('42')
assert 42i == Integer.valueOf('42') // 小写i可读性更好
assert 123L == Long.valueOf("123") // 大写L可读性更好
assert 2147483648 == Long.valueOf('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45')// default BigDecimal type used
assert .321 == new BigDecimal('.321')
assert 1.200065D == Double.valueOf('1.200065')
assert 1.234F == Float.valueOf('1.234')
assert 1.23E23D == Double.valueOf('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class ==BigInteger // octal
不同类型数值进行算术运算的规则
对于二元运算符,两个不同类型的数值进行运算后它们的结果按照以下规则确定
- 对于byte、char、short、int这几种类型之间运算的结果为int
- 涉及long与byte、char、short、int之间运算的结果为long
- 涉及BigInteger与其它类型数值之间的运算结果为BigInteger
- BigDecimal与byte、char、short、int之间的运算结果为BigDecimal
- float、double与BigDecimal之间的运算结果为double
- 两个BigDecimal之间的运算结果为BigDecimal
集合类型
Groovy 没有自己的集合类型,它的 List 类型实际上用的就是 JDK 中的 Java.util.List 包。当我们定义一个集合对象,Groovy 默认采用 java.util.ArrayList 类型。
Groovy 使用 ,
把集合中的元素分隔开,外面用 [ ]
包裹。下面使定义集合对象的例子:
groovy
def numbers = [1, 2, 3]
assert numbers instanceof List
assert numbers.size() == 3
也可以在集合中放置不同类型的元素,例如:
groovy
def heterogeneous = [1, "a", true]
默认定义的集合对象属于 java.util.ArrayList 类,也可以用 as 运算符,强制定义 List 接口的其他实现类的对象,例如:
groovy
def arrayList = [1, 2, 3]
assert arrayList = instanceof java.util.ArrayList
def linkedList [1, 2, 3] as LinkedList
assert arrayList = instanceof java.util.LinkedList
LinkedList otherLinked = [3, 4, 5]
assert otherLinked instanceof java.util.LinkedList
访问 List 集合中的元素使用 [ ]
下标运算符,其中的数值可以使正值,也可以是负值,例如:
groovy
def letters = ['a', 'b', 'c', 'd']
assert letters[0] == 'a'
assert letters[1] == 'b'
assert letters[-1] == 'd'
assert letters[-2] == 'c'
letters << 'e' // 使用左移运算符,在集合末尾添加元素
assert letters[4] == 'e'
assert letters[-1] == 'e'
Groovy 可以定义多维集合,例如:
groovy
def multi = [[0, 1], [2, 3]]
assert multi[1][0] == 2
数组
Groovy 中数组和集合的表示方式相同,也就是说 Groovy 复用 list 的表示形式来表示数组,但必须显式的声明数组的类型,例如:
groovy
String[] arrStr = ['aaa', 'bbb', 'ccc']
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
使用 as 运算符,强制转为要定义的类型
groovy
def numArr = [1, 2, 3] as int[]
assert numArr instanceof int[]
也可以定义多维数组
groovy
def matrix3 = new Integer[2][3] // 定义一个二维数组,并指定元素个数
assert matrix3.size() == 2
assert matrix3.length == 2
Integer[][] matrix2
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]
访问数组元素时按照和 list 一样的方式,使用下表运算符 []
,例如:
groovy
String[] names = ['aaa', 'bbb', 'ccc', 'ddd']
names[2] = 'eee'
assert names[2] == 'eee'
Java 风格数组初始化
groovy
def primes = new int[] {1, 2, 3, 4, 5, 6}
assert primes.size() == 5 && primes.sum() == 21
def pets = new String[] {'cat', 'dog'}
assert pets.size() == 2 && pets.sum() == 'catdog'
// Groovy 定义初始化数组方式
String[] groovyBooks = ['Groovy in Action', 'Making Java Groovy']
assert groovyBooks.every{ it.contains('Groovy')}
map
Groovy 使用中括号定义一个 map, map 中的 key/value 对用逗号分隔,例如:
groovy
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000'
assert colors.green == '#00FF00'
colors['pink'] = '#FF00FF' // 使用 [] 增加一个新的 key/value
colors.yellow = '#FFFF00' // 也可以使用 . 新增一个 key/value
说明:
Groovo 定义的 map 对象实际上是 java.util.LinkedHashMap 类的实例
key 值不光可以用 string 也可以用其他数据类型,比如:整型
groovy
def numbers = [1: 'one', 2: 'two']
下面的离职中用 key 这个变量定义一个 key,它的值为 name,但 Groovy 会认为,map 中的 key 是变量本身而不是赋予它的值。
groovy
def key = 'name'
def person = [key: 'Guillaume']
assert !person.containsKey('name')
assert person.containsKey('key')
如果要给 map 里传变量名,必须使用这种形式 (变量名)
,例如:
groovy
person = [(key): 'Guillaume']
assert person.containsKey('name')
assert !person.containsKey('key')
运算符
算数运算符
运算符 | 作用 | 备注 |
---|---|---|
+ | 加 | 同时也是一元运算符,如:+4 |
- | 减 | 同时也是一元运算符,如:-4 |
* | 乘 | |
/ | 除 | intdiv() 专门用于整数相除 |
% | 取余 | 同时也是一元运算符,如:+4 |
** | 次幂 | 同时也是一元运算符,如:+4 |
赋值运算符
+=
-=
*=
/=
%=
**=
关系运算符
运算符 | 作用 |
---|---|
== |
相等 |
!= |
不等 |
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于等于 |
=== |
完全等于(Since Groove 3.0.0) |
!== |
完全不等于(Since Groove 3.0.0) |
下面是 groovy 判断 ===
(全等)和 !==
(不全等)运算符的示例:
groovy
import groovy.transform.EqualsAndHashCode
@EqualsAndHashCode
class Creature { String type }
def cat = new Creature(type: 'cat')
def copyCat = cat
def lion = new Creature(type: 'cat')
assert cat.is(copyCat) // Groovy 的 is() 方法判断两个对象是否相等
assert cat === copyCat // === 是 is() 的简洁操作符
assert cat !== lion // negated operator shorthand
逻辑运算符
Groovy 提供了三种逻辑运算符用于布尔表达式,分别是:
&&
: 逻辑与||
: 逻辑或!
: 逻辑非
例如:
groovy
assert true && true
assert true || false
assert !false
注:逻辑非运算符!
优先级高于逻辑与&&
,逻辑与运算符&&
优先级高于逻辑或||
,例如:
groovy
assert (!false && false ) == false
assert true || true && false
乱路运算规则
逻辑与&&
和逻辑或||
都支持短路运算,对于||
只要左边的操作数为 true,不需要再判断右边的操作数就知道整个表达式的结果为 true。对于&&
只要左边的操作数为 false,不需要再判断右边的操作数就知道整个表达式的结果为 false。
位运算符和位移运算符
Groovy 的运算符如下:
&
: 按位与|
: 按位或^
: 按位异或~
: 按位取反
位运算符的操作数为整型数值,包括 byte、short、int、long、BigInteger。如果操作数的类型是 BigInteger 那么返回结果的类型也是 BigInteger;如果操作数也是 int,返回结果也是 int;如果操作数是 long,返回结果也是 long。
Grooxy 提供了三种位移运算符,分别是:
<<
: 左移运算符>>
: 右移运算符>>>
: 右移无符号运算符
groovy
assert 12.equals(3 << 2)
assert 24L.equals(3L << 3)
assert 48G.equals(3G << 4)
条件运算符
条件运算符可用于取代 if-else 判断,例如:
groovy
if (string != null && string.length() > 0) {
result = 'Found'
} else {
result = 'Not found'
}
利用条件运算符可以写成如下形式:
groovy
result = (string != null && string.length() > 0) ? 'Found' : 'Not found'
从 Groovy3.0 开始,引入了 elvis 操作符,也就是条件运算符的简便形式,例如:
groovy
displayName = user.name ? user.name : 'Anonymous' // 正常形式
displayName = user.name ?: 'Anonymous' // elvis 操作符
对象运算符
安全导航运算符(safe navigation operator)
主要作用为避免出现 NullPointerException
异常,如果出现空指针异常,使用安全导航运算符将返回 null,而不是抛出异常,例如:
groovy
def person = Person.find (it.id == 345) // 调用find方法查找
def name = person?.name
assert name == null
直接字段访问运算符(Direct field access operator)
使用该运算符可以不用调用 get 方法而直接获取字段的值,例如:
groovy
class User {
public final String name
User(String name) { this.name = name }
String getName() { "Name: $name" }
}
def user = new User('Bob')
assert user.name == 'Name: Bob'
assert user.@name == 'Bob'
方法引用运算符(method reference operator)
方法引用运算符形如两个冒号::
,目的就是调用方法。例如:
调用 BigInteger 的 add 方法,给每个元素减0,结果仍然不变。
groovy
assert 6G == [1G, 2G, 3G].stream().reduce(0G, BigInteger::add)
3G对象属于 BigInteger 类型, 调用它的 add 方法,给每个元素加3.
groovy
assert [4G, 5G, 6G] == [1G, 2G, 3G].stream().map(3G::add).collect()
第1行代码使用方法引用运算符调用 Integer 类的构造方法创建 Integer 类对象;第2行代码同样地调用数组类的构造方法创建一个数组对象
groovy
assert [1, 2, 3] == ['1', '2', '3'].stream().map(Integer::new).collect()
def result = [1, 2, 3].stream().toArray(Integer[]::new)
正则表达式运算符
~
规则运算符
~
运算符提供了一种简单的方式来创建一个 java.util.regex.Pattern 对象,例如:
groovy
import java.util.regex.Pattern
def p = ~/foo/
assert p instanceof Pattern
println p.matcher("foo").matches()
=~
查找运算符
=~
运算符用于创建一个 java.util.regex.Matcher 对象,例如:
groovy
// 定义一个字符串
def text = "some text to match"
// 使用 =~ 运算符创建一个 Matcher 对象,匹配文本中的 match 单词
def m = text =~ /match/
==~
匹配运算符
==~
运算符和=~
运算符功能相似,只是返回结果不同,前者返回布尔值,后者返回 Matcher 对象。例如:
groovy
def n = text ==~ /match/
assert n instanceof Boolean
if (n) {
throw new RuntimeException("不是 Boolean 类")
}
Groovy 程序的组成
Groovy 提供了两种代码方式,一种是脚本,一种是类,首先我们定义一个名为 Main.groovy 的类。代码如下:
groovy
class Main {
static void main(String[] args) {
println "Hello world!"
}
}
与上面代码功能相同的脚本如下:
groovy
println 'Groovy world'
脚本与类混合
上面的脚本实际由 groovy.lang.Script 类编译成一个 class 文件,把脚本代码拷贝到 groovy.lang.Script 类的 run 方法中进行执行,实际运行的代码形如下面的内容:
groovy
import org.codehaus.groovy.runtime.InvokerHelper;
class Main extends Script {
public static void main(String... args) {
InvokerHelper.runScript(Main.class, args)
}
def run() {
println 'Groovy world!'
}
}
执行的步骤如下:
- Main.class 继承 Script 类
- 把脚本的主体内容复制到 run 方法内
- 然后自动生成 main() 方法,最后运行 run()
方法
可以在脚本中定义方法,例如:
groovy
int fib(int n ) {
n < 2 ? 1 : fib(n - 1) + fib(n - 2)
}
assert fib(10) == 89
创建的脚本类在编译后会把脚本中的所有方法装配到 run 方法中,这些对于用户来说都是透明的。
变量
在脚本中定义变量无需声明变量的类型,例如:
ini
int x = 1
int y = 2
assert x + y == 3
上面的定义与如下代码等同:
groovy
x = 1
y = 1
assert x + y == 3
这两者在语义上有一些差别,上面的例子中声明的变量属于局部变量,只在 run 方法内部可见,而下面的无声明变量定义对于其他方法可见,这对于脚本与其他应用程序共享数据就显得很重要。
Groovy 面向对象
Groovy 的类
Groovy类是数据的集合和对该数据进行操作的方法的载体,类的数据和方法用于表示问题域中的一些现实世界对象。Groovy中的类声明了该类定义的对象的状态(数据)和行为。因此,Groovy类描述了该类的实例字段和方法。
下面的示例展示了Groovy类的定义及它的组成:
groovy
class Student {
int studentId;;
String studentName;
static void main(String[] args) {
Student student = new Student();
student.studentId = 1;
student.studentName = "pipi"
}
}
getter 和 setter 方法
在任何编程语言中,总是使用 private 关键字隐藏实例成员,通过提供 getter 和 setter 方法来相应地设置和获取实例变量的值。例如下面的代码:
groovy
class Student {
int studentId;;
String studentName;
static void main(String[] args) {
Student student = new Student();
student.studentId = 1;
student.studentName = "pipi"
}
void setStudentId(int sid) {
studentId = sid;
}
int getStudentId() {
return this.studentId;
}
void setStudentName(String sname) {
studentName = sname;
}
String getStudentName() {
return this.studentName;
}
}
内部类
内部类定义在另一个类中,外层类可以访问内部类,内部类也可以使用外层类的成员变量,即使是私有的。其它类不能访问内部类。内部类的示例如下:
groovy
class Example {
static void main(String[] args) {
Outer outer = new Outer();
outer.name = "pipi"
outer.callInnerMethod()
}
}
class Outer {
String name;
def callInnerMethod() {
new Inner().methodA()
}
// 内部类
class Inner {
def methodA() {
println(name)
}
}
}
在上面的例子中我们做了以下工作:
- 创建一个名为Outer的类,它将是我们的外层类。
- 在Outer类中定义名为name的字符串。
- 在我们的外层类中创建一个内部或嵌套类。
- 在内部类中,我们可以访问在0uter类中定义的名称实例成员
继承
extends 是用于继承类的关键字,我们通过一个示例介绍 groovy 中如何继承其他类
groovy
// 定义 Example 类
class Example {
static void main(String[] args) {
Student student = new Student();
student.studentId = 1;
student.marks1 = 10;
student.name = "pipi";
println(student.name)
}
}
// 定义 Person 类
class Person {
public String name;
public Person() {}
}
// 定义 Student 类,继承 Person
class Student extends Person {
int studentId;
int marks1;
public Student() {
super()
}
}
抽象类
抽象类表示通用概念,因此它不能被实例化,但可以被继承。抽象类中的抽象方法只有方法的定义而没有方法的实现,它的实现通过继承它的类来完成,定义抽象类通过关键字 abstract 来声明,抽象方法也是同样的。下面通过一个示例展示定义和使用抽象类:
groovy
// 定义 Example 类
class Example {
static void main(String[] args) {
Student student = new Student();
student.studentId = 1;
student.marks1 = 10;
student.name = "pipi";
println(student.name)
student.displayMarks()
}
}
// 定义 Person 类
abstract class Person {
public String name;
public Person() {}
abstract void displayMarks();
}
// 定义 Student 类,继承 Person
class Student extends Person {
int studentId;
int marks1;
public Student() {
super()
}
@Override
void displayMarks() {
println(marks1)
}
}
接口
接口定义了类需要遵守的规范,接口仅定义需要实现的方法的列表,但是不定义方法实现。接口需要使用 interface 关键字声明接口,接口的方法总是公开的,在接口中使用受保护或者私有方法是一个错误。我们通过下面的示例定义一个接口:
groovy
// 定义 Example 类
class Example {
static void main(String[] args) {
Student student = new Student();
student.studentId = 1;
student.marks1 = 10;
student.displayMarks()
}
}
interface Marks {
void displayMarks();// 定义接口方法
}
// 定义 Student 类,继承 Person
class Student implements Marks {
int studentId;
int marks1;
public Student() {
super()
}
@Override
void displayMarks() {
println(marks1)
}
}
在上面的示例中:
- 创建了一个名为 Marks 的接口并创建一个名为 displayMarks 的接口方法
- 在 Student 类中,使用 implements 关键字来实现接口
- 在实现类中必须为接口中 displayMarks 方法提供实现
闭包的概念及使用
Groovy 中的闭包完全避免了冗长的代码,而且可以辅助创建轻量级、可复用的代码片段。通过一个示例来比较传统方式和使用闭包方式的不同
groovy
def sum(n) {
total = 0
for (int i = 2; i < n; i += 2) {
total += i;
}
total
}
println("sum of event nubmers from 1 to 10 is ${sum(10)}")
上述代码运行了一个 for 循环,在偶数上迭代求和
groovy
def product(n) {
prod = 1
for (int i = 2; i <= n; i += 2) {
prod *= i
}
prod
}
println("Prod of event numbers from 1 to 10 is ${product(10)}")
我们在求和代码的基础上修改一下,变成求 1 到 10 中偶数的乘积。从中提出任务的共同部分就是 for 循环,把代码改造如下:
groovy
def pickEven(n, block) {
for (int i = 2; i <= n; i += 2) {
block(i) // 指向闭包的调用
}
}
pickEven(10, {println(it)}) // {}里面是匿名代码块
在 for 循环中,变量 block 保存了一个指向闭包的引用,我们可以像传递对象一样传递闭包。变量名可以是任何合法的变量名,我们把这种匿名代码块称为闭包(Closure)。
通过闭包的方式来求 1-10 中偶数之和,代码如下:
groovy
product = 1
pickEven(10, {product *= it})
println("Prod of even numbers from 1 to 10 is ${product}")
Groovy 的闭包不能单独存在,必须附着在方法上,或者赋给一个变量。