首先,使用其中任何一种相比其他方式的性能优势很可能太小而不相关。在绝大多数情况下,代码的简洁性、可读性和可维护性更为重要。
引用块:
这里存在一个基本误解。布尔类型是一种原始类型(而非引用类型)。true和false值无法被替换为引用。此外,用于保存true和false的空间取决于上下文。通常是一个字节,远小于在64位JVM上存储引用所需的8个字节(如果oops压缩被禁用)。因此,即使在技术上可能,这种“优化”也不会节省内存。
没有你的例子涉及到创建
Boolean
实例
2,所以我们可以在性能分析中排除它。
# Example 1
boolean isItTrue(arg){
return true;
}
这个方法将会与其他所有方法一样快甚至更快,因为它只需要将一个寄存器设为零即可。
Boolean isItTrue(arg){
return Boolean.TRUE;
}
从孤立的角度来看,这需要从内存中加载一个静态引用,而不是将寄存器清零。然而,在某些情况下,即时编译器可能能够对此进行优化。
# Example 3
Boolean isItTrue(arg){
return true;
}
表面上,这涉及到调用
Boolean.valueOf(true)
来"装箱"这个
true
,但是JIT编译器应该能够通过内联调用来优化它,使其与之前的代码相同。
boolean isItTrue(arg){
return Boolean.TRUE
}
表面上看,这涉及到调用
Boolean.booleanValue(Boolean.TRUE)
来“拆箱”
Boolean
。这个调用可以内联。同时,即时编译器也有可能避免加载对
Boolean
对象的引用并获取其值字段。
总结一下,你的四个例子的相对性能取决于JIT编译器在优化方面的成功程度。这将取决于上下文、JIT编译器的具体设置等等。理论上,JIT编译器可以为所有例子生成相同(最优)的代码。实际上,在几乎所有情况下,差异都是微不足道的。(而且这本身也不是一个实际的例子。)
1 - 这个基准测试无意中证明了这一点。如果它所呈现的结果是可信的,那么最好和最差版本之间的性能差异每次调用不到1纳秒。
2 - 理论上有可能其中4个触发了Boolean
类的初始化,并且你的应用程序本来不会这样做。在这种极不可能的情况下,你的整个应用程序将分配2个本来不会被分配的对象。初始化可能需要几微秒,并且在长期内消耗几个字节的RAM(少于50字节)。这在实践中是无关紧要的。