Groovy中for循环的一个奇怪现象引出的"全局变量?"

原创
2015/02/04 23:38
阅读数 840

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

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部