在Java中,我们看到很多地方可以使用final关键字,但它的使用并不常见。
例如:
String str = "abc";
System.out.println(str);
在上面的例子中,str可以是final,但通常不使用。
当一个方法永远不会被覆盖时,我们可以使用final关键字。类似地,类不会被继承。
在任何或所有这些情况下使用final关键字真的能提高性能吗?如果是,那该怎么做?请解释一下。如果final的正确使用确实关系到性能,那么Java程序员应该养成什么样的习惯才能最好地利用这个关键字呢?
简单的回答:不用担心!
长一点的回答:
在讨论final局部变量时,请记住使用关键字final将帮助编译器静态优化代码,这可能最终导致更快的代码。例如,下面示例中的最终字符串a + b是静态连接的(在编译时)。
public class FinalTest {
public static final int N_ITERATIONS = 1000000;
public static String testFinal() {
final String a = "a";
final String b = "b";
return a + b;
}
public static String testNonFinal() {
String a = "a";
String b = "b";
return a + b;
}
public static void main(String[] args) {
long tStart, tElapsed;
tStart = System.currentTimeMillis();
for (int i = 0; i < N_ITERATIONS; i++)
testFinal();
tElapsed = System.currentTimeMillis() - tStart;
System.out.println("Method with finals took " + tElapsed + " ms");
tStart = System.currentTimeMillis();
for (int i = 0; i < N_ITERATIONS; i++)
testNonFinal();
tElapsed = System.currentTimeMillis() - tStart;
System.out.println("Method without finals took " + tElapsed + " ms");
}
}
结果呢?
Method with finals took 5 ms
Method without finals took 273 ms
在Java Hotspot VM 1.7.0_45-b18上测试。
那么实际性能提高了多少呢?我不敢说。在大多数情况下可能是微不足道的(在这个合成测试中大约为270纳秒,因为完全避免了字符串连接——这种情况很少见),但在高度优化的实用程序代码中,它可能是一个因素。在任何情况下,对最初问题的答案都是肯定的,它可能会提高性能,但充其量只能提高一点点。
除了编译时的好处,我找不到任何证据表明使用关键字final对性能有任何可衡量的影响。
你实际上在问两种(至少)不同的情况:
局部变量的Final
方法/类的Final
Jon Skeet已经回答了2)。关于1):
我不认为这有什么区别;对于局部变量,编译器可以推断该变量是否是final变量(只需检查它是否被多次赋值)。因此,如果编译器想要优化只赋值一次的变量,无论变量是否声明为final,它都可以这样做。
Final可能会对protected/public类字段产生影响;在那里,编译器很难发现字段是否被设置了不止一次,因为它可能发生在不同的类中(甚至可能没有被加载)。但即使这样,JVM也可以使用Jon描述的技术(乐观地优化,如果加载了更改字段的类,则恢复)。
总之,我看不出有任何理由它应该有助于性能。
所以这种微观优化不太可能有帮助。您可以尝试对其进行基准测试以确定,但我怀疑它是否会产生影响。
编辑:
实际上,根据Timo Westkämper的回答,final在某些情况下可以提高类字段的性能。我接受纠正。