Groovy提供了一些非常方便的方式来实现接口。
如果一个接口只有一个方法,那么可以使用闭包来实现,如下:
new Thread( {println "running"} as Runnable ).start()
你也可以使用闭包来实现一个含有多个方法的接口,此时闭包将被接口上的每个方法调用。有时候你需要一个含有参数列表的闭包来满足所有的方法,那么使用一个数组类型的参数是典型的做法,而且此做法可以在任意的Groovy闭包上使用,Groovy会将所有的参数放到一个数组当中,比如:
interface X { void f(); void g(int n); void h(String s, int n); } x = {Object[] args -> println "method called with $args"} as X x.f() x.g(1) x.h("hello",2)
通常含有多个方法的接口一般是用映射来实现,比如:
impl = [ i: 10, hasNext: { impl.i > 0 }, next: { impl.i-- }, ] iter = impl as Iterator while ( iter.hasNext() ) println iter.next()
注意 这是一个非常人为的例子,但确实解释了概念。
一般来说你只需要实现那些你实际调用的方法即可,但是如果调用一个在map中不存在的方法,将抛出NullPointerException异常,比如:
interface X { void f(); void g(int n); void h(String s, int n); } x = [ f: {println "f called"} ] as X x.f() //x.g() // NPE here空指针
要注意
不要偶尔使用{}来定义map,你能猜出下面代码将会是什么结果么?
x = { f: {println "f called"} } as X x.f() x.g(1)
此处我们定义了一个带标签和代码块的闭包,由于我们在此只是定义了一个闭包,因此每一个方法调用都将调用此闭包。某些语言是使用{ }来定义映射的,因此很容易跟Groovy的定义映射([:])的方式混淆。
注意
在上述示例中,“as”操作符的使用将要求我们用映射实现的接口有一个静态的引用(static reference 即要知道接口的类型,译者注)。如果只有一个java.lang.Class对象的引用来表示要用到的接口(比如根本不知道或者不想在脚本里边硬编码)呢?那你可以使用asType方法来实现,如下:
def loggerInterface = Class.forName( 'my.LoggerInterface' ) def logger = [ log : { Object[] params -> println "LOG: ${params[0]}"; if( params.length > 1 ) params[1].printStackTrace() }, close : { println "logger.close called" } ].asType( loggerInterface )
更多参考: