初学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是静态方法.