在Java中使用final关键字可以提高性能吗?
  在Java中,我们看到很多可以使用final关键字的地方,但它的使用并不常见。 
例如:
String str = "abc";
System.out.println(str);
  在上面的例子中, str可以是final但这通常是中止的。 
当一个方法永远不会被覆盖时,我们可以使用final关键字。 同样的情况下,一个类不会被继承。
  在任何或所有这些情况下使用final关键字是否真的可以提高性能?  如果是这样,那么怎么样?  请解释。  如果正确使用final对于性能确实非常重要,那么Java程序员应该开发哪些习惯来充分利用关键字? 
通常不会。 对于虚拟方法,HotSpot会跟踪方法是否已被实际覆盖,并且能够执行优化,比如假设方法没有被覆盖,直到它加载一个覆盖方法的类,此时它可以撤销(或部分撤消)这些优化。
(当然,这是假设你正在使用HotSpot--但它是迄今为止最常见的JVM,所以......)
  在我看来,您应该根据清晰的设计和可读性使用final ,而不是出于性能原因。  如果出于性能原因想要更改任何内容,则应在将最清晰的代码弯曲变形之前执行适当的测量 - 通过这种方式,您可以决定是否有任何额外的性能值得阅读/设计较差。  (根据我的经验,这几乎是不值得的; YMMV。) 
  编辑:作为最后的领域已被提及,值得提出的是,无论如何,他们往往是一个好主意,在清晰的设计方面。  它们还根据跨线程可见性更改了保证的行为:构造函数完成后,任何最终字段都将保证在其他线程中立即可见。  根据我的经验,这可能是final中最常见的用法,尽管作为Josh Bloch的“继承或禁止设计的经验”的支持者,我应该更经常地使用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关键词对性能有任何可衡量的影响。 
  编辑:当使用javap -c FinalTest.class反编译代码时,获得以下指令: 
 public static java.lang.String testFinal();
    Code:
       0: ldc           #16                 // String a
       2: astore_0
       3: ldc           #18                 // String b
       5: astore_1
       6: ldc           #20                 // String ab
       8: areturn
  public static java.lang.String testNonFinal();
    Code:
       0: ldc           #16                 // String a
       2: astore_0
       3: ldc           #18                 // String b
       5: astore_1
       6: new           #24                 // class java/lang/StringBuilder
       9: dup
      10: aload_0
      11: invokestatic  #26                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      14: invokespecial #32                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      17: aload_1
      18: invokevirtual #35                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #39                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      24: areturn
  由于testFinal()方法的指令少于testNonFinal() ,因此速度会更快。 
是的,它可以。 这是一个最终可以提升性能的例子:
条件编译是一种技术,根据特定条件,代码行不会编译到类文件中。 这可以用来删除生产版本中的大量调试代码。
考虑以下:
public class ConditionalCompile {
  private final static boolean doSomething= false;
    if (doSomething) {
       // do first part. 
    }
    if (doSomething) {
     // do second part. 
    }
    if (doSomething) {     
      // do third part. 
    }
    if (doSomething) {
    // do finalization part. 
    }
}
通过将doSomething属性转换为最终属性,您告诉编译器,只要它看到doSomething,就应该按照编译时替换规则将其替换为false。 编译器的第一遍将代码更改为如下所示:
public class ConditionalCompile {
  private final static boolean doSomething= false;
    if (false){
       // do first part. 
    }
    if (false){
     // do second part. 
    }
    if (false){
      // do third part. 
    }
    if (false){
    // do finalization part. 
    }
}
一旦完成,编译器会再次查看它,并发现代码中存在无法访问的语句。 由于您正在使用高质量的编译器,因此它不喜欢所有那些无法访问的字节码。 所以它将它们删除,最终得到这个结果:
public class ConditionalCompile {
  private final static boolean doSomething= false;
  public static void someMethodBetter( ) {
    // do first part. 
    // do second part. 
    // do third part. 
    // do finalization part. 
  }
}
从而减少任何过多的代码或任何不必要的条件检查。
编辑:作为一个例子,我们来看下面的代码:
public class Test {
    public static final void main(String[] args) {
        boolean x = false;
        if (x) {
            System.out.println("x");
        }
        final boolean y = false;
        if (y) {
            System.out.println("y");
        }
        if (false) {
            System.out.println("z");
        }
    }
}
  在使用Java 8编译此代码并使用javap -c Test.class反编译时,我们得到: 
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return
  public static final void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: iload_1
       3: ifeq          14
       6: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       9: ldc           #22                 // String x
      11: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      14: iconst_0
      15: istore_2
      16: return
}
  我们可以注意到,编译后的代码只包含非最终变量x 。  这证明最终变量对性能有影响,至少对于这种简单的情况。 
上一篇: Does use of final keyword in Java improve the performance?
