Groovy(八)-程序结构

译文:Groovy Language Documentation
主目录见:Android高级进阶知识(这是总目录索引)

这章将会覆盖所有Groovy编程语言中的程序结构。

1.3.1包名
包名和java中的包名用法是一样的,它允许我们对代码进行分包而不会有冲突。Groovy 必须在类定义之前明确它的包名,不然就会使用默认包名。

定义包的方式和java一样:

// defining a package named com.yoursite
package com.yoursite

想要引用com.yoursite.com包中的类Foo,你需要指定全类名com.yoursite.com.Foo,或者你可以使用import来声明。

1.3.2Imports(导入)
为了引用一个类你必须明确引用一个包,Groovy允许你使用java的关键字import来引用你的类。

例如,Groovy 提供了几个builder类,如MarkupBuilderMarkupBuilder类在包groovy.xml中,所以要使用这个类,你必须这样使用import:

// importing the class MarkupBuilder
import groovy.xml.MarkupBuilder

// using the imported class to create an object
def xml = new MarkupBuilder()

assert xml != null

默认导入
默认导入的意思是Groovy语言中默认已经导入了这些包,例如这些代码:

new Date()

在java中,这样的代码是需要这样导入Date类的:import 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

之所以这样做是因为这些是比较通用的,这样避免了一些样板代码。

简单导入
简单导入的意思是你导入类的时候加上了完整的包名,例如你使用import导入import groovy.xml.MarkupBuilder就是一个简单导入,直接引用了包中的某一个类:

// importing the class MarkupBuilder
import groovy.xml.MarkupBuilder

// using the imported class to create an object
def xml = new MarkupBuilder()

assert xml != null

星形(*)导入
Groovy跟java一样,提供了一个简单的方式(*)来引用包中的所有类,例如MarkupBuilder类在包groovy.xml中,同时另外一个类StreamingMarkupBuilder也在这个包中,如果你想同时使用这个包中的这两个类的话可以这么做:

import groovy.xml.MarkupBuilder
import groovy.xml.StreamingMarkupBuilder

def markupBuilder = new MarkupBuilder()

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

这当然是正确的代码,但是使用*导入的话,你只需要一行,就导入了包中groovy.xml所有的类:

import groovy.xml.*

def markupBuilder = new MarkupBuilder()

assert markupBuilder != null

assert new StreamingMarkupBuilder() != null

*导入有一个问题是他会打乱你的本地命名空间,但是用Groovy的别名很容易解决这个问题。

静态(static)导入
Groovy的静态导入引用类跟你引用本类的静态方法一样:

import static Boolean.FALSE

assert !FALSE //use directly, without Boolean prefix!

这个跟java中的静态导入一样,但是Groovy中会更具动态特征,它允许你定义相同名字的方法,只要方法参数类型不一样:

import static java.lang.String.format            1

class SomeClass {

    String format(Integer i) {                   2
        i.toString()
    }

    static void main(String[] args) {
        assert format('String') == 'String'      3
        assert new SomeClass().format(Integer.valueOf(1)) == '1'
    }
}

1.静态导入方法
2.声明和静态导入的方法一样的名字,但是参数类型不一样
3.在java中会编译错误,但是在Groovy中会通过
如果你的参数类型一样,那么导入类的优先级会更高

静态导入别名
静态导入使用as关键字来优雅地解决命名空间问题,假如你想使用getInstance()方法来获得Calendar实例,这是个静态方法,所以我们要使用静态导入,但是为了避免每次都调用getInstance()方法,而且和他的类分开的话容易引起误导,所以我们可以使用别名增加代码的可读性:

import static Calendar.getInstance as now

assert now().class == Calendar.getInstance().class

这样代码就很干净了。
静态星形导入
静态星形导入和通常的星形导入非常相似,他将会导入指定类中的所有静态方法。

例如,我们需要在我们的应用中计算sines 和cosines 值,在java.lang.Math中有我们需要的方法名sincos,通过我们的静态星形导入,我们可以这么做:

import static java.lang.Math.*

assert sin(0) == 0.0
assert cos(0) == 1.0

正如我们所看到的,我们直接使用sincos方法,而不需要添加Math.前缀.

导入别名
通过类型别名,我们可以选择一个别名来命名我们引用的指定类名,跟之前一样,这也可以通过as关键字来做。

例如你能将java.sql.Date作为SQLDate导入,而且能在同一个文件里面使用而不需要使用类的全限定名。

import java.util.Date
import java.sql.Date as SQLDate

Date utilDate = new Date(1000L)
SQLDate sqlDate = new SQLDate(1000L)

assert utilDate instanceof java.util.Date
assert sqlDate instanceof java.sql.Date

1.3.3.脚本和类对比
public static void main 和脚本
Groovy支持脚本和类,下面是示例代码:

Main.groovy
class Main {                                    1
    static void main(String... args) {          2
        println 'Groovy world!'                 3
    }
}

1.定义一个Main类,名字可以随意
2.public static void main(String[])方法和类中的main方法用法一致
3.main方法的主体

这个是能在java代码中找到的典型代码,需要放进类中才可以执行,Groovy使他变得简单化了,下面代码是等价的:

Main.groovy
println 'Groovy world!'

一个脚本被认为是一个类,而不需要去声明他。

脚本类
一个脚本总是被编译成一个类,Groovy的编译器会为你编译它,脚本内容会被拷贝进一个run方法里面,之前的例子会被编译成如下代码:

Main.groovy
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {                     1
    def run() {                                 2
        println 'Groovy world!'                 3
    }
    static void main(String[] args) {           4
        InvokerHelper.runScript(Main, args)     5
    }
}

1.Main类继承了groovy.lang.Script
2.groovy.lang.Script需要一个run方法来返回值
3.脚本内容被放进run方法里
4.Main方法是自动产生的
5.代理执行脚本的run方法
如果脚本在一个文件中,这样文件的名字被用来决定生成脚本类的名字,在这个例子中,如果文件名是Main.groovy,脚本名字就会是Main。

方法
在脚本中定义方法也是可行的,如下:

int fib(int n) {
    n < 2 ? 1 : fib(n-1) + fib(n-2)
}
assert fib(10)==89

你也可以混合方法和代码,生成的脚本类将会携带所有的方法,而且会组建所有的脚本内容到run方法中。

println 'Hello'                                 1

int power(int n) { 2**n }                       2

println "2^6==${power(6)}"                      3

1.脚本开始
2.在脚本内容中定义方法
3.脚本其余部分

这段代码被转化成:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
    int power(int n) { 2** n}                   1
    def run() {
        println 'Hello'                         2
        println "2^6==${power(6)}"              3
    }
    static void main(String[] args) {
        InvokerHelper.runScript(Main, args)
    }
}

1.power方法将会被拷贝进生成的脚本类中
2.第一个声明被拷贝进run
3.第二个声明也被拷贝进run

虽然Groovy从脚本帮你创建了脚本类,但是对用户来说是透明的,特别是,代码被编译成字节码,行数是被保持的。这是为了当有一个异常抛出的时候,堆栈会显示出行号对应的原始代码,而不是生成的代码。

变量
在脚本中的类型不需要类型定义,意思就是说像下面代码:

int x = 1
int y = 2
assert x+y == 3

我们可以像下面这么做:

x = 1
y = 2
assert x+y == 3

然而这两者的语义上面还有所不同:
1.像第一个例子中的变量定义,他是一个局部变量,他将会被编译器声明在run方法中,脚本main主体是不可见的,特别地,这类变量不会被其他方法可见。
2.如果变量未声明,那么他就会变成脚本绑定,这个变量在方法间是可见的,尤为重要的是你需要用一个脚本跟应用打交道或者需要在脚本与应用间共享数据的时候。读者可以通过 integration guide来获取更多信息.

如果你不想通过绑定来使变量成为类的全局变量的话,那么你可以使用@Field annotation(变量注解)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容