我想知道标记为 final 的变量是如何被Groovy解释的(在1.8.0,1.8.1中)。我知道它在Java中是有意义的,它可以提高性能 - 当然 - 有助于避免愚蠢的错误。我想了解 final 是否可以帮助java编译器优化用Groovy编写的程序。我想知道Groovy变换器是否保留变量的最终标记。
答案 0 :(得分:17)
groovyc
似乎不会像javac那样内联最终变量。我创建了两个测试脚本,一个使用final,一个不使用:
final String message = "Hello World"
println message
String message = "Hello World"
println message
javap -c
为这两个类产生了相同的输出:
0: invokestatic #18; //Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite; 3: astore_1 4: ldc #58; //String Hello World 6: astore_2 7: aload_1 8: ldc #59; //int 1 10: aaload 11: aload_0 12: aload_2 13: invokeinterface #63, 3; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object; 18: areturn 19: nop
javac
优化了astore
/ aload
:
没有final
:
0: ldc #2; //String Hello World 2: astore_1 3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream; 6: aload_1 7: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 10: return
使用final
:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Hello World 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return
所有这一切,如果性能至关重要,Groovy开始时是一个糟糕的选择。内联最终变量不会为您节省使用反射进行方法调用的开销。
答案 1 :(得分:12)
作为Justin has said,如果编译器对最终变量执行的优化对您很重要,那么您不应该使用Groovy。
但是,如果Groovy的性能足够好,那么将变量标记为final仍然有用,原因有两个:
保护类的不变量,即确保在构造对象后无法更改值。 Java在编译时强制执行此操作,Groovy仅在运行时强制执行此操作,但这比静默允许更改不可变值更好
文档。您班级的用户可以轻松查看允许更改的值
答案 2 :(得分:3)
还没有。但它可能在未来,所以我仍然在适当时标记它们。