Ska*_*rab 15 optimization groovy final
我想知道标记为final的变量是如何被Groovy解释的(在1.8.0,1.8.1中).我知道它在Java中是有意义的,它可以提高性能 - 当然 - 有助于避免愚蠢的错误.我想学习final是否可以帮助java编译器优化用Groovy编写的程序.我想知道Groovy变换器是否保留变量的最终标记.
Jus*_*per 17
似乎没有groovyc像javac那样内联最终变量.我创建了两个测试脚本,一个使用final,一个不使用:
final String message = "Hello World"
println message
Run Code Online (Sandbox Code Playgroud)
String message = "Hello World"
println message
Run Code Online (Sandbox Code Playgroud)
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开始时是一个糟糕的选择.内联最终变量不会为您节省使用反射进行方法调用的开销.
Dón*_*nal 13
正如Justin所说,如果编译器对最终变量执行的优化对您很重要,那么您不应该使用Groovy.
但是,如果Groovy的性能足够好,那么将变量标记为final仍然有用,原因有两个:
保护类的不变量,即确保在构造对象后不能更改值.Java在编译时强制执行此操作,Groovy仅在运行时强制执行此操作,但这比静默允许更改不可变值更好
文档.您班级的用户可以轻松查看允许更改的值