初学Groovy, 用for循环的时候出现了点问题,记录下来
环境: Eclipse4.4, Groovy编译器版本 2.3.7 Java版本:1.8_23_x86
看下面在Java中比较常见的代码
for(int i=0, j=0; i<5; i++, j++){ System.out.println(i + ", " + j); }
于是我想当然的在Groovy中照着写了一个,
for(int i=0, j=0; i<5; i++, j++){ println "$i , $j"); } //编译错误(具体位置在 i=0 ) //unexpected token: = at line: 1, column: 10
居然不支持, 于是问了下谷姐, 发现确实是不支持. 链接: http://stackoverflow.com/questions/14535123/groovy-for-loop-with-multiple-counters
机智如我, 有怎么会被区区编译错误拦住, 换个方式
for(int i=j=0; i<5; i++, j++){ println "$i, $j" } //编译错误(具体位置在 , j++) //expecting ')', found ',' at line: 1, column: 24
好吧, 不能j++就算了, 我放循环里面去, 终于可以执行了
for(int i=j=0; i<5; i++){ println "$i, $j" j++ } //再减少一行 for(int i=j=0; i<5; i=++j){ println "$i, $j" } //输出 0, 0 1, 1 2, 2 3, 3 4, 4
好了, 不报错了,舒服了...那么问题来了, 为什么这么可以~~~~~于是抄起字节码开看,关键位置
28 goto 169 31 iconst_0 32 istore_2 33 iload_2 34 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [67] 37 ldc <Class main.Temp> [2] 39 aload_0 [this] 40 ldc <String "j"> [69] 42 invokestatic org.codehaus.groovy.runtime.ScriptBytecodeAdapter.setGroovyObjectProperty(java.lang.Object, java.lang.Class, groovy.lang.GroovyObject, java.lang.String) : void [73] 45 iload_2 46 istore_3 [i] 47 iload_3 [i]
原来如此, 大概翻译过来就是(真是的更复杂点,但大概是这样的, i++这样的代码似乎变成了方法调用)
ScriptBytecodeAdapter.setGroovyObjectProperty(0, 当前类class, 当前类实例, "j"); for(int i = 0; i<5;){ println xxxxx ScriptBytecodeAdapter.setGroovyObjectProperty(PogoGetPropertySite.getProperty("j") + 1, 当前类class, 当前类实例, "j"); i = PogoGetPropertySite.getProperty("j") }
大家可以断点试试.
那么为什么会出现这个情况了, 猜测: 可能是类似于js全局变量的概念
int i = j = 0 被翻译为了
int i= 0
j = 0
而全局变量底层实现是放在一个LinkedHashMap中的.
由于是脚本,估计j被当作全局变量类似的东西, 来证明下猜想
for(int i=j=0; i<2; i=++j){ k = 1 println "$i, $j" } println "$k" //输出1 println "$j" //输出2 println "$i" //异常, i不存在
可以看到, i的范围在for内, 而j在for外也能访问, 有点类似于全局变量.
最后说明下, 上面的代码放在main方法里面是会报错的~~~只能实例方法中, main是静态方法.