匿名类中的Groovy脚本字段访问

时间:2013-09-10 17:53:52

标签: java groovy anonymous-class

在Groovy 2.1.6脚本中,我正在定义一个字段:

import groovy.transform.Field
@Field String test = "abc";

println "Script: ${test}";
def run = new Runnable() {
    void run() {
        println "Runnable0: ${test}";
        new Runnable() {
            void run() {
                println "Runnable1: ${test}";
            }
        }.run();
    }
}.run();

当从脚本中的匿名类(如here)访问它时,Groovy似乎尝试将此Field强制转换为Reference,并在定义Runnable后立即抛出以下异常:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'groovy.lang.Reference'
    at bug1.run(bug1:5)

此外,如果我将匿名Runnables放在像here这样的函数中,Groovy在转换时没有问题,但是在内部Runnable中找不到Field:

groovy.lang.MissingFieldException: No such field: test for class: bug2$1
    at bug2$1.this$dist$get$1(bug2.groovy)
    at bug2$1$2.propertyMissing(bug2.groovy)
    at bug2$1$2.run(bug2.groovy:14)
    at java_lang_Runnable$run.call(Unknown Source)
    at bug2$1.run(bug2.groovy:12)
    at java_lang_Runnable$run.call(Unknown Source)
    at bug2.fun(bug2.groovy:9)
    at bug2.run(bug2.groovy:5)

这可以通过重新定义像here这样的字段来解决 ,但此修复仅适用于函数

这是Groovy中的错误还是我违反了一些规则而Groovy只缺少正确的异常?

2 个答案:

答案 0 :(得分:2)

如果您调用匿名类并引用字段变量,则不需要进行@Field转换。

<强>原因:
当脚本中的严格类型变量定义为@Field时,该变量(在编译时[AST转换])在该脚本中被视为私有。因此财产缺失。

为了实现差异,只需从Groovy控制台可视化AST浏览器中的脚本,并在两种情况下都进行“语义分析”阶段(没有和使用@Field),你会注意到变量是{{{ 1}}用于主脚本,与分别全局定义相比。

<强>推论
另一方面,当在同一脚本内的方法中使用严格类型化的变量时,run()转换很有用,因为没有@Field该字段将被声明为{{1}中的局部变量脚本的方法,因此对其他方法不可见。

摘自AST browser了解详情。

答案 1 :(得分:0)

由于Groovy闭包已经Runnable,你可以这样做:

import groovy.transform.Field
@Field String test = "abc";

println "Script: ${test}";
{ -> 
    println "Runnable0: ${test}";
    { -> 
        println "Runnable1: ${test}"
    }.run()
}.run()

哪个有用