前言:
官方关于Programm Structure的介绍:Programm Structure
下文将会介绍Groovy的程序结构。
1.包名 Package names
这里的包名同Java中的包名发挥着同样的角色。包名允许我们分隔代码从而避免冲突。Groovy类必须在定义之前指定他们的包,并且假设默认的包名存在。
定义包的方式和Java非常相似
// defining a package named com.yoursite package com.yoursite
你可以调用Foo类使用com.yoursite.com.Foo,当然下面也将介绍import声明的方式引用类。
2.导包 Imports
为了引用任意一个类,而不需要包名。Groovy遵从了Java的方式允许使用import声明来解决类的导入。
例如,Groovy提供了几个builder类,例如MarkupBuilder。MarkupBuilder类在groovy.xml包中,所有你可以使用该类,通过以下方式的导入:
// importing the class MarkupBuilder import groovy.xml.MarkupBuilder // using the imported class to create an object def xml = new MarkupBuilder() assert xml != null
2.1. 默认导入 Default imports
new Date()
同样的代码在Java中则需要导包声明:java.util.Date。Groovy默认为你导入了这些类。
Groovy默认添加了以下导入:
import java.lang.* import java.util.* import java.io.* import java.net.* import groovy.lang.* import groovy.util.* import java.math.BigInteger import java.math.BigDecimal
之所以这样做,是因为这些类非常常用。通过默认导入,减少了代码量。
2.2. 简单导包 Simple import
简单导包是你使用类的全路径进行导包。例如下面:
// importing the class MarkupBuilder import groovy.xml.MarkupBuilder // using the imported class to create an object def xml = new MarkupBuilder() assert xml != null
2.3. 星号导入 Star import
像Java一样,Groovy提供了一个特殊的方式导入包下的所有的类通过使用*,也就是所谓的星号导包。实行星号导包前的导入方式:
import groovy.xml.MarkupBuilder import groovy.xml.StreamingMarkupBuilder def markupBuilder = new MarkupBuilder() assert markupBuilder != null assert new StreamingMarkupBuilder() != null
使用星号导包后:
import groovy.xml.* def markupBuilder = new MarkupBuilder() assert markupBuilder != null assert new StreamingMarkupBuilder() != null
2.4.静态导包 Static import
在Groovy的静态导包允许你导入类之后可以向静态方法一样在你自己的类中。和Java的静态导入相似,但是在Java1.4之上才能正常工作。
用法和Java基本相似,不再赘述:
import static Boolean.FALSE assert !FALSE //use directly,without Boolean prefix!
2.5.静态导包别名 Static import aliasing
这种用法比较类似于C语言中的typedef的用法。
使用as关键字的静态导包为命名空间问题提供了一个简洁的解决方案。加入你想要获得一个Calendar实例,使用getInstance()方法。它是静态方法,所以你可以使用静态导入。如果采用静态发导入,在调用时将不带类名因此容易误导使用者。我们可以使用别名的形式进行导入,以增强阅读性。
import static Calendar.getInstance as Now assert Now().class == Calendar.getInstance().class
这样变得非常简洁易读。
2.6.静态星号导入 Static star import
星号静态导入和规则的星号导入很相似。将会导入该类的所有的静态的方法。
例如,下面的例子:
import static java.lang.Math.* assert sin(0) == 0.0 assert cos(0) == 1.0
2.7 别名导入 Import aliasing
使用别名,我们可以使用自定义的名称来指向一个完全的类。同上,可以通过as关键字来实现。
考虑以下类,假设由第三方的类库提供的:
package thirdpartylib public class MultiplyTwo { def static multiply(def value) { return value * 3 //intentionally wrong. } }
假如我们这样使用这个库:
def result = new MultiplyTwo().multiply(2)
现在假设有这样一种情况,在使用了这个第三方库并且贯穿了你所有的代码,我们发现它没有给出一个正确的结果。我们怎样在一处修改,而不是修改源码,而不改变其他使用的地方?Groovy提供了简洁的方案。
使用简单的别名导入,我们可以修复这个bug像这样:
import thirdpartylib.MultiplyTwo as OrigMultiplyTwo class MultiplyTwo extends OrigMultiplyTwo { def multiply(def value) { return value * 2 // fixed here } } // nothing to change below here def multiplylib = new MultiplyTwo() // assert passes as well assert 4 == new MultiplyTwo().multiply(2)
这就是通过as关键字重命名导入的类解决了这个问题。
别名导入在解决星号导入时的命名冲突同样有用。
3.脚本vs类 Script versus classes
3.1. public static void main vs 脚本 public static void main vs script
Groovy同时支持class和script(即类和脚本)。使用一下代码作为例子:
Main.groovy
class Main { //定义一个Main类,名字是任意的 static void main(String... args) { println 'Groovy world!' } }
你会发现以上是Java中的典型代码,代码嵌入类中执行。而Groovy是的这些变得更加容易,以下代码是等价的:
Main.groovy
println 'Groovy world!'
你可以把脚本想象成是一个不用声明的类。
3.2 脚本类 Script class
脚本总是会被编译成类。Groovy编译器会为你编译这个类,会把脚本体复制进run方法。上面的例子会被编译如下:
Main.groovy
import org.codehaus.groovy.runtime.InvokerHelper class Main extends Script { //Main类继承了groovy.lang.Script类 def run() { //groovy.lang.Script需要run方法返回一个值 println 'Groovy world!' } static void main(String[] args) { //自动生成 InvokerHelper.runScript(Main,args) } }
如果脚本是一个文件,文件的基本名称会被用于生成脚本类。在这个例子中,如果文件名是Main.groovy,之后脚本类的会被命名为Main。
3.3. 方法Methods
定义方法在脚本中是可以的,如下:
int fib(int n) { n < 2 ? 1 : fib(n-1) + fib(n-2) } assert fib(10)==89
你可以将方法和代码混合。生成的脚本类会将所有的方法带入脚本类,并且嵌入所有的脚步体到run方法中:
println 'Hello' //脚步开始处 int power(int n) { 2**n } //一个没有脚本体的方法 println "2^6==${power(6)}"//脚本
以上代码会被转化成:
import org.codehaus.groovy.runtime.InvokerHelper class Main extends Script { int power(int n) { 2** n}//power方法被复制进了自动生成的脚本类里面 def run() { println 'Hello' //脚本被复制到了这里面 println "2^6==${power(6)}" } static void main(String[] args) { InvokerHelper.runScript(Main,args) } }
尽管Groovy通过你的脚本创建了一个类,不过这个类对用户来说依然是易懂的。特别的,脚本被编译成字节码,行号被保留。这就意味着如果脚本中出现了一个异常,异常记录将会返回相应的原始脚本的行号,而不是你自动生成类的行号。
3.4. 变量Variables
变量在脚本中不需要类型声明。这就意味着,如下脚本:
int x = 1 int y = 2 assert x+y == 3
等同于:
x = 1 y = 2 assert x+y == 3
然而,二者之间在语义学上是不同的,表现如下:
- 如果声明变量如同第一个例子,它是本地变量。将会被声明在run方法,在脚本外部不可用。特别的,这种变量在脚本的其他方法中不可见。
- 如果变量没有被声明,变量会被绑定到脚本。并且对其他方法可见,你使用脚本与其他程序交互需要传递数据在脚本和程序之间,这种声明是非常有用的。
如果你希望变量变成一个类的字段而不是在Binding中,你可以使用@Field annotation.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。