[TOC]
概述 Groovy特点
同时支持静态与动态类型
支持运算符重载
对于正则表达式的本地支持
对xml和html的原生支持
与Java无缝衔接
安装 可以参考Groovy官网上的方式,利用SDK来安装Groovy。
基本语法 Helloword 1 2 3 4 5 6 7 8 9 class HelloWorld { static void main(String[] args){ println('hello world); } } //如果用Groovy脚本的方式: println ' hello world'
导入 1 2 import groovy.xml.MarkupBuilderdef xml = new MarkupBuilder()
默认情况下,Groovy在代码中包括了一些库,不需要显示的导入。
1 2 3 4 5 6 7 8 9 10 java.lang.*; java.util.*; java.io.*; java.net.*; groovy.lang.*; groovy.util.*; java.math.BigInteger; java.math.BigDecimal;
Groovy语句 语句可以是一个关键字,一个标识符,常量,字符串文字或者是符号
注释 参考Java的就可以
分号 Groovy可以不用写分号一行就是一条语句
声明 Groovy声明变量的方式是利用def 关键字。标识符以字母,美元或者下划线开头。
1 2 3 def employeedef studentdef conter
字符 浮点数,整数,字符和字符串
1 2 3 4 5 def i = 12 def j = 12.5 def a = 'a' def s1 = "aaa" def s2 = 'aaaaaaa'
数据类型 内置数据类型
byte
short
int
long
float
double
char
boolean
String
数字类(Number)
Byte
Short
Integer
Long
Float
Double
BigInteger
BIgDecimal
变量 变量的声明有两种:
一种是类似Java的方式声明,一种是利用def关键字,变量的类型在赋值的时候去确定。
1 2 3 4 5 6 7 String a = "hello" def a = 'hello' def a = 1 println(a.getClass()) a = new String("1112234" ) println(a.getClass())
//利用def的方式,变量的类型还可以随时动态的切换
运算符
算术运算符
关系运算符
逻辑运算符
位运算符
赋值运算符
主要介绍一下Groovy比Java多出的一些特性
范围运算符
1 2 3 def range = 0. .5 println(range.class ) println(range)
输出
1 2 class groovy.lang.IntRange [0, 1, 2, 3, 4, 5]
流程控制 循环 while
for 1 2 3 4 5 6 7 8 9 10 11 12 13 14 for (;;){ } for (var in range){ } def e = ["a" :12 ,"b" :31 ,"c" :12 ,"d" :32 ]for (a in e){ println(a) }
break 终止内层循环
continue 当执行continue语句时,控制立即传递到最近的封闭循环的测试条件,以确定循环是否应该继续。对于该特定循环迭代,循环体中的所有后续语句都将被忽略。
条件 if if-else switch 方法 Groovy用def关键字定方法。方法可以接受任意数量参数,可不用显示定义类型。可以添加修饰符,默认的是public的。
1 2 3 def methodName(parm1, param2, param3){ }
参数 可以添加任意多个参数,并且可以指定默认参数,但是默认参数必须定义在参数列表的末尾。
1 2 3 def someMethod(param1, param2. param3 = 3 ){ }
返回值 1 2 3 4 5 6 def add (x, y, z = 3 , w = 4 ){ x + y + z + w; } s = add(1 ,2 ) println(s)
上面的代码,默认的返回最后一行表达式的值。
但是为了避免歧义:我们可以通过这种方式来进行:
1 2 3 4 5 6 7 8 9 def int add(x ,y){ x + y } def add(x, y){ return x + y }
文件I/O Groovy在使用IO时提供了许多辅助方法。Groovy提供了更简单的类来为文件提供以下功能:
读取文件
写入文件
遍历文件树
读取和写入数据对象到文件
也可以使用java.io.*下面的所有标准Java类
读取文件 1 2 3 new File("/Users/hefuduo/hefuduo.profile" ).eachLine { line -> println line }
如果要将文件的整个内容作为字符串获取,可以使用文件类的text属性。
1 2 File fi = new File("/Users/hefuduo/hefuduo.profile" ) println fi.text
或者使用Java提供的InputStream
1 2 3 4 5 File fi = new File("/Users/hefuduo/hefuduo.profile" ) InputStream it = new FileInputStream(fi) it.eachLine { println it }
写入文件 1 2 3 4 5 File fi = new File("/Users/hefuduo/hefuduo.profile" ) fi.withWriter { it.append("Job : computer engineer" ) } println fi.text
以追加的形式写入文件:
1 2 3 4 5 6 7 8 9 File fi = new File ("/Users/hefuduo/hefuduo.profile" )OutputStream stream = new FileOutputStream (fi,true )stream.withWriter { it.write("age:27" ) } stream.close() fi.eachLine { println it }
获取文件大小 1 2 3 File fi = new File("/Users/hefuduo/hefuduo.profile" ) println fi.absolutePath println fi.length()
测试文件是否是目录 1 2 println fi.isFile() println fi.isDirectory()
创建与删除目录 1 2 3 File fi = new File("/Users/hefuduo/dirtest/" ) fi.mkdir() fi.delete()
复制文件 1 2 3 4 File fi = new File("/Users/hefuduo/hefuduo.profile" ) def src = fidef dst = new File(fi.absolutePath)dst << src.text
获取目录中的所有内容 1 2 3 4 5 6 File fi = new File("/Users/hefuduo/" ) def files = fi.listFiles()println files.length files.each { println it.name }
如果要递归的显示目录与子目录中的所有文件,则可以使用File了eachFileRecurse函数。
1 2 3 4 5 File fi = new File("/Users/hefuduo/" ) fi.eachFileRecurse { file -> println file.getAbsolutePath() }
Groovy 可选 Groovy是个动态类型语言,相对Java的强类型语言,Groovy在编写代码时候,可以灵活的提供类型或不是类型。
Groovy内部数据 Groovy数字 在Groovy中,数字实际上标识为对象,他们都是类Integer的一个实例。
Groovy支持整数和浮点数
1 2 Integer x = 5 Float y = 1.25
装箱与拆箱 1 2 3 def x = 5 , y = 6 , z = 0 z = x + y println z
Groovy字符串 Groovy提供了多种表示String字面量的方法。 Groovy中的字符串可以用单引号(’),双引号(“)或三引号(”“”)括起来。此外,由三重引号括起来的Groovy字符串可以跨越多行。
字符串索引 1 2 3 4 5 6 String sample = "Hello Groovy" println sample[4 ] println sample[-1 ] println sample[1. .2 ] println sample[4. .2 ] println sample[-2 ]
Groovy范围 范围是指定值序列的速记。范围由序列中的第一个和最后一个值表示,Range可以是包含或排除。包含范围包括从第一个到最后一个的所有值,而独占范围包括除最后一个之外的所有值。这里有一些范例文字的例子 -
1..10 - 包含范围的示例
1 .. <10 - 独占范围的示例
‘a’..’x’ - 范围也可以由字符组成
10..1 - 范围也可以按降序排列
‘x’..’a’ - 范围也可以由字符组成并按降序排列。
Groovy列表 列表是用于存储数据项集合的结构。在Groovy中,List保存了一系列对象引用。List中的对象引用占据序列中的位置,并通过整数索引来区分。列表文字表示为一系列用逗号分隔并用方括号括起来的对象。
要处理列表中的数据,我们必须能够访问各个元素。 Groovy列表使用索引操作符[]索引。列表索引从零开始,这指的是第一个元素。
以下是一些列表的示例 -
[11,12,13,14] - 整数值列表
[‘Angular’,’Groovy’,’Java’] - 字符串列表
[1,2,[3,4],5] - 嵌套列表
[‘Groovy’,21,2.11] - 异构的对象引用列表
[] - 一个空列表
Groovy映射 映射(也称为关联数组,字典,表和散列)是对象引用的无序集合。Map集合中的元素由键值访问。 Map中使用的键可以是任何类。当我们插入到Map集合中时,需要两个值:键和值。
以下是一些映射的例子 -
[‘TopicName’:’Lists’,’TopicName’:’Maps’] - 具有TopicName作为键的键值对的集合及其相应的值。
[:] - 空映射。
在本章中,我们将讨论Groovy中可用的映射方法。
1 2 3 4 5 def aMap = ['TopicName' :'Lists' ,'TopicName2' :'Maps' ]aMap.each { key,value -> println("key = $key" + "value = $value" ) }
Groovy正则表达式 正则表达式是用于在文本中查找子字符串的模式。 Groovy使用〜“regex”表达式本地支持正则表达式。引号中包含的文本表示用于比较的表达式。
例如,我们可以创建一个正则表达式对象,如下所示 -
当Groovy运算符=〜在if和while语句(见第8章)中作为谓词(返回布尔值的表达式)出现时,左侧的String操作数与右侧的正则表达式操作数匹配。因此,以下每个都传递值true。
当定义正则表达式时,可以使用以下特殊字符
有两个特殊的位置字符用于表示一行的开始和结束:caret(∧)和美元符号($)。
正则表达式也可以包括量词。加号(+)表示一次或多次,应用于表达式的前一个元素。星号(*)用于表示零个或多个出现。问号(?)表示零或一次。
元字符{和}用于匹配前一个字符的特定数量的实例。
在正则表达式中,句点符号(。)可以表示任何字符。这被描述为通配符。
正则表达式可以包括字符类。一组字符可以作为简单的字符序列,包含在元字符[和]中,如[aeiou]中。对于字母或数字范围,可以使用[a-z]或[a-mA-M]中的短划线分隔符。字符类的补码由方括号内的前导插入符号表示,如[∧a-z]中所示,并表示除指定的字符以外的所有字符。
1 2 3 4 5 6 7 'Groovy' =~ 'Groovy' 'Groovy' =~ 'oo' 'Groovy' ==~ 'Groovy' 'Groovy' ==~ 'oo' 'Groovy' =~ '∧G' ‘Groovy' =~ ' G$' ‘Groovy' =~ 'Gro*vy' 'Groovy' =~ 'Gro{2}vy'
1 2 def regex = ~'groovy' println ("groovy" .matches(regex))
面向对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Empire { private String name int age Empire(String name,int age){ this .name = name this .age = age } def getName(){ return name } } Empire empire = new Empire("China" ,5000 ) println empire.getName() println empire.name println empire.age
继承&扩展 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 interface FLY { def fly() } class Animal { private String name private String category Animal(String name, String category) { this .name = name this .category = category } String getName() { return name } String getCategory() { return category } void setName(String name) { this .name = name } void setCategory(String category) { this .category = category } } class Dove extends Animal implements FLY { Dove(String name, String category) { super (name, category) } @Override def fly() { println "I believe i can fly" } } Dove d = new Dove("Dove" ,"Bird" ) println d.name println d.category d.fly() Dove f = new Dove("" ,"" ) f.name = "lala" f.category = "prettyBird" println f.name println f.category
内部类 下面是一个外部和内部类的例子。在下面的例子中,我们做了以下事情 -
创建一个名为Outer的类,它将是我们的外部类。
在Outer类中定义名为name的字符串。
在我们的外类中创建一个内部或嵌套类。
请注意,在内部类中,我们可以访问在Outer类中定义的名称实例成员。
其实Groovy中的内部类和Java中的是一样的
抽象类 同上
1 2 3 4 5 6 7 8 9 10 11 abstract class ABTest { abstract def test() } class AB extends ABTest { @Override def test() { return null } }
接口 接口定义了类需要遵守的契约。接口仅定义需要实现的方法的列表,但是不定义方法实现。需要使用interface关键字声明接口。接口仅定义方法签名。接口的方法总是公开的。在接口中使用受保护或私有方法是一个错误。
Groovy 泛型 可以参考Java的泛型,他们是一样的。(因为Groovy也是基于JVM)
Groovy特征 特征是语言的结构构造,允许 -
行为的组成。
接口的运行时实现。
与静态类型检查/编译的兼容性
它们可以被看作是承载默认实现和状态的接口。使用trait关键字定义trait。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 trait SwimmingAbility { def swim(){ println "${this.class} is swimming" } } trait FlyingAbility { def fly(){ println "${this.class} is flying" } } interface Eat { def eat() } class Duck implements SwimmingAbility ,FlyingAbility,Eat{ @Override def eat() { return null } } Duck d = new Duck() d.fly() d.swim() trait Name implements FlyingAbility , SwimmingAbility{ public String name abstract def printName() } class Person implements Name { public String name @Override def printName() { println Name__name } } Person p = new Person() p.Name__name = "hefuduo" p.name = "LeoHe" p.swim() p.fly() def foo(String str){ str?.reverse() } println foo(null)
##实现接口
Traits可以实现接口,在这种情况下,使用implements关键字声明接口。
属性 特征可以定义属性。下面给出了具有属性的trait的示例。
在以下示例中,integer类型的Marks1是一个属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Example { static void main(String[] args) { Student st = new Student(); st.StudentID = 1 ; println(st.DisplayMarks()); println(st.DisplayTotal()); } interface Total { void DisplayTotal() } trait Marks implements Total { int Marks1; void DisplayMarks() { this .Marks1 = 10 ; println(this .Marks1); } void DisplayTotal() { println("Display Total" ); } } class Student implements Marks { int StudentID } }
行为的构成 特征可以用于以受控的方式实现多重继承,避免钻石问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 trait Name implements FlyingAbility , SwimmingAbility{ public String name abstract def printName() } class Person implements Name { public String name @Override def printName() { println Name__name } } Person p = new Person() p.Name__name = "hefuduo" p.name = "LeoHe" p.swim() p.fly()
Groovy闭包 闭包是一个短的匿名代码块。它通常跨越几行代码。一个方法甚至可以将代码块作为参数。它们是匿名的。
下面是一个简单闭包的例子,它是什么样子。
1 2 3 4 def close = { println "hello groovy" } close.call()
闭包中的形式参数 闭包也可以包含形式参数,以使它们更有用,就像Groovy中的方法一样。
1 2 3 4 5 6 7 8 def closure = { suffix -> println "hello $suffix" } closure.call("world" )
闭包和变量 更正式地,闭包可以在定义闭包时引用变量。以下是如何实现这一点的示例。
1 2 3 4 5 6 7 8 9 10 11 def closure = { param -> println param } def fin(String logan,Closure s){ s.call(logan) } fin("hefuduo" ,closure)
集合和字符串中的闭包 几个List,Map和String方法接受一个闭包作为参数。让我们看看在这些数据类型中如何使用闭包的例子。
使用闭包和列表 以下示例显示如何使用闭包与列表。在下面的例子中,我们首先定义一个简单的值列表。列表集合类型然后定义一个名为.each的函数。此函数将闭包作为参数,并将闭包应用于列表的每个元素
使用映射闭包 以下示例显示了如何使用闭包。在下面的例子中,我们首先定义一个简单的关键值项Map。然后,映射集合类型定义一个名为.each的函数。此函数将闭包作为参数,并将闭包应用于映射的每个键值对。
Groovy注解 注释是元数据的形式,其中它们提供关于不是程序本身的一部分的程序的数据。注释对它们注释的代码的操作没有直接影响。
注释主要用于以下原因 -
编译器信息 -编译器可以使用注释来检测错误或抑制警告。
编译时和部署时处理 -软件工具可以处理注释信息以生成代码,XML文件等。
运行时处理 -一些注释可以在运行时检查。
字符串类型 1 2 3 4 @interface Simple{ String str1() default "hi" }
枚举类型 1 2 3 4 enum DayOfWeek {Mon, Tue, Wed, Thu, Sat, Sun}@interface Scheduled{ DayOfWeek dayOfWeek() }
类类型 1 2 3 4 5 6 7 @interface Simple{} @Simple Class User{ }
注释成员值 使用注释时,需要至少设置所有没有默认值的成员。下面给出一个例子。当定义后使用注释示例时,需要为其分配一个值。
关闭注释参数 Groovy中注释的一个很好的特性是,你也可以使用闭包作为注释值。因此,注释可以与各种各样的表达式一起使用。
下面给出一个例子。注释Onlyif是基于类值创建的。然后注释应用于两个方法,它们基于数字变量的值向结果变量发布不同的消息。
1 2 3 4 5 6 7 8 9 10 11 12 13 @interface OnlyIf { Class value() } @OnlyIf ({ number<=6 }) void Version6() { result << 'Number greater than 6' } @OnlyIf ({ number>=6 }) void Version7() { result << 'Number greater than 6' }
元注释 这是groovy中注释的一个非常有用的功能。有时可能有一个方法的多个注释,如下所示。有时这可能变得麻烦有多个注释。
1 2 3 @Procedure @Master class MyMasterProcedure {}
在这种情况下,您可以定义一个元注释,它将多个注释集中在一起,并将元注释应用于该方法。所以对于上面的例子,你可以使用AnnotationCollector来定义注释的集合。
1 2 3 4 5 import groovy.transform.AnnotationCollector @Procedure @Master @AnnotationCollector
一旦完成,您可以应用以下元注释器到该方法 -
1 2 3 4 5 6 7 8 import groovy.transform.AnnotationCollector @Procedure @Master @AnnotationCollector @MasterProcedure class MyMasterProcedure {}
Groovy XML XML 生成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import groovy.xml.MarkupBuilderdef mB = new MarkupBuilder()mB.collection(shelf: 'New Arrivals' ) { movie(title: 'Enemy Behind' ) type('War, Thriller' ) format('DVD' ) year('2003' ) rating('PG' ) stars(10 ) description('Talk about a US-Japan war' ) } mB.Html(){ header(ref : "www.baidu.com" ) body{ h1("hello world" ) } }
XML解析 Groovy XmlParser类使用一个简单的模型来将XML文档解析为Node实例的树。每个节点都有XML元素的名称,元素的属性和对任何子节点的引用。这个模型足够用于大多数简单的XML处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <collection shelf ="New Arrivals" > <movie title ="Enemy Behind" > <type > War, Thriller</type > <format > DVD</format > <year > 2003</year > <rating > PG</rating > <stars > 10</stars > <description > Talk about a US-Japan war</description > </movie > <movie title ="Transformers" > <type > Anime, Science Fiction</type > <format > DVD</format > <year > 1989</year > <rating > R</rating > <stars > 8</stars > <description > A schientific fiction</description > </movie > <movie title ="Trigun" > <type > Anime, Action</type > <format > DVD</format > <year > 1986</year > <rating > PG</rating > <stars > 10</stars > <description > Vash the Stam pede!</description > </movie > <movie title ="Ishtar" > <type > Comedy</type > <format > VHS</format > <year > 1987</year > <rating > PG</rating > <stars > 2</stars > <description > Viewable boredom</description > </movie > </collection >
解析代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def parser = new XmlParser()def doc = parser.parse("assets/movies.xml" )doc.movie.each { bk -> print "Movie Name : " println "${bk['@title']}" print "Movie Type : " println "${bk.type[0].text()}" print "Movie Format : " println "${bk.format[0].text()}" print "Movie year : " println "${bk.year[0].text()}" print "Rating : " println "${bk.rating[0].text()}" print "Starts : " println "${bk.stars[0].text()}" print "Description : " println "${bk.description[0].text()}" println "=============================" }
重要的事情需要注意上面的代码。
正在形成类XmlParser的对象,以便它可以用于解析XML文档。
解析器被给定XML文件的位置。
对于每个电影元素,我们使用闭包浏览每个子节点并显示相关信息。
对于movie元素本身,我们使用@符号显示附加到movie元素的title属性。
Groovy JMX JMX 用于监控与Java虚拟机环境有任何关系的所有应用程序。
监视JVM 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import java.lang.management.*def os = ManagementFactory.operatingSystemMXBeanprintln """OPERATING SYSTEM: OS architecture = $os.arch OS name = $os.name OS version = $os.version OS processors = $os.availableProcessors """ def rt = ManagementFactory.runtimeMXBeanprintln """RUNTIME: Runtime name = $rt.name Runtime spec name = $rt.specName Runtime vendor = $rt.specVendor Runtime spec version = $rt.specVersion Runtime management spec version = $rt.managementSpecVersion """ def mem = ManagementFactory.memoryMXBeandef heapUsage = mem.heapMemoryUsagedef nonHeapUsage = mem.nonHeapMemoryUsageprintln """MEMORY: HEAP STORAGE: Memory committed = $heapUsage.committed Memory init = $heapUsage.init Memory max = $heapUsage.max Memory used = $heapUsage.used NON-HEAP STORAGE: Non-heap memory committed = $nonHeapUsage.committed Non-heap memory init = $nonHeapUsage.init Non-heap memory max = $nonHeapUsage.max Non-heap memory used = $nonHeapUsage.used """ println "GARBAGE COLLECTION:" ManagementFactory.garbageCollectorMXBeans.each { gc -> println " name = $gc.name" println " collection count = $gc.collectionCount" println " collection time = $gc.collectionTime" String[] mpoolNames = gc.memoryPoolNames mpoolNames.each { mpoolName -> println " mpool name = $mpoolName" } }
Groovy JSON JSON功能
功能
库
JsonSlurper
JsonSlurper是一个将JSON文本或阅读器内容解析为Groovy数据的类结构,例如地图,列表和原始类型,如整数,双精度,布尔和字符串。
JsonOutput
此方法负责将Groovy对象序列化为JSON字符串。
反序列化 1 2 3 4 5 6 7 8 9 10 11 12 import groovy.json.JsonSlurperdef slurper = new JsonSlurper()def obj = slurper.parseText('{"name":"John","id":"1"}' )println obj.name println obj.id def lst = slurper.parseText('{"List" : [2,3,4,5]}' )lst.each { key, value -> println("$key = $value" ) }
序列化 1 2 3 4 5 6 7 8 9 10 import groovy.json.JsonOutputdef jsonOuter = new JsonOutput()Map<String, Object> map = new HashMap<>() map.put("name" ,"hefuduo" ) map.put("age" ,27 ) map.put("ss" ,new Car(14 )) String json = jsonOuter.toJson(map) println json
Groovy DLS Groovy允许在顶层语句的方法调用的参数周围省略括号。这被称为“命令链”功能。这个扩展的工作原理是允许一个人链接这种无括号的方法调用,在参数周围不需要括号,也不需要链接调用之间的点。
如果一个调用被执行为bcd,这将实际上等价于a(b).c(d)。
DSL或域特定语言旨在简化以Groovy编写的代码,使得它对于普通用户变得容易理解。以下示例显示了具有域特定语言的确切含义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class EmailDSL { String toText String fromText String body def static make(Closure closure){ EmailDSL dsl = new EmailDSL() closure.delegate = dsl closure.call() } def to(String toText){ this .toText = toText } def from(String fromText){ this .fromText = fromText } def body(String bodyText){ this .body = bodyText } def send(boolean send){ if (send){ println "From $fromText To $toText : $body" } } } EmailDSL.make { to "James" from "Leo" body "How is everything going on" send true }
使用接受闭包的静态方法。这是一个很麻烦的方式来实现DSL。
在电子邮件示例中,类EmailDsl具有make方法。它创建一个实例,并将闭包中的所有调用委派给实例。这是一种机制,其中“to”和“from”节结束了EmailDsl类中的执行方法。
一旦to()方法被调用,我们将文本存储在实例中以便以后格式化。
我们现在可以使用易于为最终用户理解的简单语言调用EmailDSL方法。
Groovy 模板引擎 字符串中的简单模板 如果你采用下面的简单例子,我们首先定义一个名称变量来保存字符串“Groovy”。在println语句中,我们使用$符号来定义可以插入值的参数或模板。
1 2 def name = "Groovy" println "This Tutorial is about ${name}"
如果上面的代码在groovy中执行,将显示以下输出。输出清楚地显示$名称被由def语句分配的值替换
简单模板引擎 以下是SimpleTemplateEngine的示例,它允许您在模板中使用类似于JSP的scriptlet和EL表达式,以生成参数化文本。模板引擎允许绑定参数列表及其值,以便可以在具有定义的占位符的字符串中替换它们。
1 2 3 4 5 6 7 8 9 def text ='This Tutorial focuses on $TutorialName. In this tutorial you will learn about $Topic' def binding = ["TutorialName" :"Groovy" , "Topic" :"Templates" ] def engine = new groovy.text.SimpleTemplateEngine() def template = engine.createTemplate(text).make(binding) println template
如果上面的代码在groovy中执行,将显示以下输出。
现在让我们使用XML文件的模板功能。作为第一步,让我们将下面的代码添加到一个名为Student.template的文件中。在以下文件中,您将注意到,我们尚未添加元素的实际值,而是添加占位符。所以$ name,$ is和$ subject都被放置为占位符,需要在运行时替换。
1 2 3 4 5 6 <Student> <name>${name}</name> <ID>${id}</ID> <subject>${subject}</subject> </Student>
现在,让我们添加我们的Groovy脚本代码来添加功能,可以使用实际值替换上面的模板。应该注意以下事项关于以下代码。
占位符到实际值的映射通过绑定和SimpleTemplateEngine完成。绑定是一个映射,占位符作为键,替换值作为值。
1 2 3 4 5 6 7 8 9 10 11 import groovy.text.* import java.io.* def file = new File("D:/Student.template" ) def binding = ['name' : 'Joe' , 'id' : 1 , 'subject' : 'Physics' ] def engine = new SimpleTemplateEngine() def template = engine.createTemplate(file) def writable = template.make(binding) println writable
如果上面的代码在groovy中执行,将显示以下输出。从输出中可以看出,在相关占位符中成功替换了值。
1 2 3 4 5 <Student > <name > Joe</name > <ID > 1</ID > <subject > Physics</subject > </Student >
Groovy 元对象编程 元对象编程或MOP可以用于动态调用方法,并且可以即时创建类和方法。
那么这是什么意思呢?让我们考虑一个叫Student的类,它是一个没有成员变量或方法的空类。假设你必须在这个类上调用以下语句。
1 2 3 Def myStudent = new Student() myStudent.Name = ”Joe”; myStudent.Display()
现在在元对象编程中,即使类没有成员变量Name或方法Display(),上面的代码仍然可以工作。
这如何工作?那么,为了这个工作,一个人必须实现GroovyInterceptable接口挂钩到Groovy的执行过程。以下是该接口的可用方法。
1 2 3 4 5 6 7 Public interface GroovyInterceptable { Public object invokeMethod(String methodName, Object args) Public object getproperty(String propertyName) Public object setProperty(String propertyName, Object newValue) Public MetaClass getMetaClass() Public void setMetaClass(MetaClass metaClass) }
所以在上面的接口描述中,假设你必须实现invokeMethod(),它会被调用的每个方法,要么存在或不存在。
缺失属性 所以,让我们看一个例子,我们如何为缺失的属性实现元对象编程。以下键应该注意以下代码。
类Student没有定义名为Name或ID的成员变量。
类Student实现GroovyInterceptable接口。
有一个称为dynamicProps的参数,将用于保存即时创建的成员变量的值。
方法getproperty和setproperty已被实现以在运行时获取和设置类的属性的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Example { static void main(String[] args) { Student mst = new Student(); mst.Name = "Joe" ; mst.ID = 1 ; println(mst.Name); println(mst.ID); } } class Student implements GroovyInterceptable { protected dynamicProps=[:] void setProperty(String pName,val) { dynamicProps[pName] = val } def getProperty(String pName) { dynamicProps[pName] } }
以下代码的输出将是 -
缺失方法 所以,让我们看一个例子,我们如何为缺失的属性实现元对象编程。以下键应该注意下面的代码 -
类学生现在实现invokeMethod方法,它被调用,而不管该方法是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Example { static void main(String[] args) { Student mst = new Student(); mst.Name = "Joe"; mst.ID = 1; println(mst.Name); println(mst.ID); mst.AddMarks(); } } class Student implements GroovyInterceptable { protected dynamicProps = [:] void setProperty(String pName, val) { dynamicProps[pName] = val } def getProperty(String pName) { dynamicProps[pName] } def invokeMethod(String name, Object args) { return "called invokeMethod $name $args" } }
以下代码的输出如下所示。请注意,即使方法Display不存在,也没有缺少方法异常的错误。