javac是否优化" foo" .length()?

时间:2015-09-01 15:12:13

标签: java string jvm javac

如果我在代码中有这个语句/ literal:

"foobar".length()

它是否被6的编译器取代?或者它是否在内化实例上调用该方法?将这样的东西放在代码而不是无意义的东西中更具可读性6,但我不想一遍又一遍地调用这个方法,尽管我知道它只是一种吸气剂对于私人领域。

如果是,是否由javac的某种白名单完成,哪些方法在编译时可以安全地评估文字(或者也许所有不采用任何参数的方法,并且不要依赖于环境状态(?))可能​​的副作用等等。

1 个答案:

答案 0 :(得分:4)

它不会被javac取代:在Java字节码中,您将看到对length()方法的显式调用。但是在JIT编译期间,它可能会被常量替换,因为JIT编译器足够聪明,可以内联length()方法并检测它返回常量字符串的最终数组字段的长度。

通常,Java字节码的优化很少。大部分辛勤工作都是在JIT编译期间完成的。不过,在这种情况下你不应该担心性能:热代码将被JIT编译。

为了证明我的答案,这是一个简单的方法:

public static long lengthTest() {
    long sum = 0;
    for(int i=1; i<="abcdef".length(); i++) sum+=i*2;
    return sum;
}

这里是字节码:

 0: lconst_0        
 1: lstore_0        
 2: iconst_1        
 3: istore_2        
 4: iload_2         
 5: ldc             #5   // String abcdef
 7: invokevirtual   #6   // Method java/lang/String.length:()I
10: if_icmpgt       26   
13: lload_0         
14: iload_2         
15: iconst_2        
16: imul            
17: i2l             
18: ladd            
19: lstore_0        
20: iinc            2, 1 
23: goto            4    
26: lload_0         
27: lreturn         

正如您所看到的那样,显式调用length()

这里是JIT编译的代码(x64 ASM):

sub $0x18,%rsp
mov %rbp,0x10(%rsp)  ;*synchronization entry
                     ; - Test::lengthTest@-1 (line 12)
mov $0x2a,%eax
add $0x10,%rsp
pop %rbp
test %eax,-0x260e95c(%rip)  # 0x0000000000330000
                            ;   {poll_return}
retq

正如您所看到的,整个方法体在技术上被替换为单个常量(mov $0x2a,%eax,0x2a为42,这是该方法的实际结果)。所以JIT编译器不仅内联了length(),它还将整个方法体计算为常量!