栏目导航
热点推荐
- 三十条有用的 Java 编程规则
- Java制作水印图片源码
- Java常见异常及可能的导致原因
- Java中的修饰词使用方法总结
- J2EE系统异常的处理准则
- Java中的异常、断言、日志解析(
- Java面试技巧:Java面试题集锦(
- 面向Java开发人员的Scala指南:
- Java程序员:一刻钟精通正则表达
- 网友经验分享:学好java开发的关
- 专家解答:创建表格与数据库进行
- Java远程访问Domino数据库
阅览排行
实战 Groovy: @Delegate 注释
www.jz123.cn 2009-10-09 来源: 中国建站 责任编辑(袁袁) 我要投递新闻
在过去几期 实战 Groovy 文章中,您已经了解了闭包和元编程之类的 Groovy 语言特性如何将动态功能添加到 Java™ 开发中。本文提供了更多这方面的内容。您将看到 @Delegate 注释如何演变自 ExpandoMetaClass 使用的 delegate。您将再一次领略到 Groovy 的动态功能如何使它成为单元测试的理想语言。
在 “使用闭包、ExpandoMetaClass 和类别进行元编程” 一文中,您了解了 delegate 的概念。当将一个 shout() 方法添加到 java.lang.String 的 ExpandoMetaClass 中时,您使用 delegate 来表示两个类之间的关系,如清单 1 所示:
清单 1. 使用 delegate 访问 String.toUpperCase()
String.metaClass.shout = {-> return delegate.toUpperCase() } println "Hello MetaProgramming".shout() //output HELLO METAPROGRAMMING |
您不能表示为 this.toUpperCase(),因为 ExpandoMetaClass 并未包含 toUpperCase() 方法。类似地,也不能表示为 super.toUpperCase(),因为 ExpandoMetaClass 没有扩展 String。(事实上,它不可能扩展 String,因为 String 是一个 final 类)。Java 语言并不具备用于表示这两个类之间的共生关系的词汇。这就是为什么 Groovy 要引入 delegate 概念。
在 Groovy 1.6 中,@Delegate 注释被添加到该语言中。(从 参考资料 部分可以获得添加到 Groovy 1.6 中的所有新注释的列表)。该注释允许您向任意 类添加一个或多个委托 — 而不仅仅是 ExpandoMetaClass。
要充分地认识到 @Delegate 注释的威力,考虑 Java 编程中一个常见但复杂的任务:在 final 类的基础上创建一个新类。
复合模式和 final 类
假设您希望创建一个 AllCapsString 类,它具有 java.lang.String 的所有行为,唯一的不同是 — 正如名称暗示的那样 — 值始终以大写的形式返回。String 是一个 final 类 — Java 演化到尽头的产物。清单 2 证明您无法直接扩展 String:
清单 2. 扩展 final 类是不可能的
class AllCapsString extends String{ } $ groovyc AllCapsString.groovy org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed, AllCapsString.groovy: 1: You are not allowed to overwrite the final class 'java.lang.String'. @ line 1, column 1. class AllCapsString extends String{ ^ 1 error |
这段代码无效,因此您的下一个最佳选择就是使用符合模式,如清单 3 所示(有关复合模式的更多信息,请参见 参考资料):
清单 3. 对 String 类的新类型使用复合模式
class AllCapsString{ final String body AllCapsString(String body){ this.body = body.toUpperCase() } String toString(){ body } //now implement all 72 String methods char charAt(int index){ return body.charAt(index) } //snip... //one method down, 71 more to go... } |
因此,AllCapsString 类拥有 一个 String,但是其行为 不同于 String,除非您映射了所有 72 个 String 方法。要查看需要添加的方法,可以参考 Javadocs 中有关 String 的内容,或者运行清单 4 中的代码:
清单 4. 输出 String 类的所有方法
String.class.methods.eachWithIndex{method, i-> println "${i} ${method}" } //output 0 public boolean java.lang.String.contentEquals(java.lang.CharSequence) 1 public boolean java.lang.String.contentEquals(java.lang.StringBuffer) 2 public boolean java.lang.String.contains(java.lang.CharSequence) ... |
将 72 个 String 方法手动添加到 AllCapsString 并不是一种明智的方法,而是在浪费开发人员的宝贵时间。这就是 @Delegate 注释发挥作用的时候了
上一篇:编程技巧:JAVA连接数据库的代码 下一篇:启动Java应用的Shell脚本的方法