在Java中,我们看到很多地方可以使用final关键字,但它的使用并不常见。

例如:

String str = "abc";
System.out.println(str);

在上面的例子中,str可以是final,但通常不使用。

当一个方法永远不会被覆盖时,我们可以使用final关键字。类似地,类不会被继承。

在任何或所有这些情况下使用final关键字真的能提高性能吗?如果是,那该怎么做?请解释一下。如果final的正确使用确实关系到性能,那么Java程序员应该养成什么样的习惯才能最好地利用这个关键字呢?


当前回答

注意:不是java专家

如果我没有记错我的java,使用final关键字几乎没有办法提高性能。 我一直知道它的存在是为了“好代码”——设计和可读性。

其他回答

通常不会。对于虚方法,HotSpot会跟踪该方法是否实际被重写,并且能够在假定某个方法没有被重写的情况下执行优化,例如内联——直到它加载一个重写该方法的类,这时它可以撤销(或部分撤销)那些优化。

(当然,这是假设你正在使用HotSpot -但它是迄今为止最常见的JVM,所以…)

在我看来,使用final应该基于清晰的设计和可读性,而不是出于性能考虑。如果您出于性能原因想要更改任何内容,那么应该在修改最清晰的代码之前执行适当的度量——这样您就可以决定以较差的可读性/设计换取额外的性能是否值得。(根据我的经验,这几乎不值得;YMMV)。

EDIT: As final fields have been mentioned, it's worth bringing up that they are often a good idea anyway, in terms of clear design. They also change the guaranteed behaviour in terms of cross-thread visibility: after a constructor has completed, any final fields are guaranteed to be visible in other threads immediately. This is probably the most common use of final in my experience, although as a supporter of Josh Bloch's "design for inheritance or prohibit it" rule of thumb, I should probably use final more often for classes...

I cannot say it is uncommon because as far as I know it is the only way of declaring a constant in java. As a javascript developer, I know how important the keyword constant is. If you are working in production level, and you have values that can never be changed even accidentally by other coders, values such as SSN number or even names. Then you have to use the final keyword to declare variables. Sometimes it can be very troublesome if certain classes can be inherited. Because if many people are working in a team someone can inherit a class, extend it and even make changes to the variables and methods of the parent class. This can be stopped with the keyword final because even static variables can be changed unless the final keyword is used. As far as your question is concerned I do not think the final keyword can affect the performance of the code, but it can definitely prevent human errors by making sure that other team members do not accidentally modify anything that needs to remain constant.

根据IBM的说法——它不用于类或方法。

http://www.ibm.com/developerworks/java/library/j-jtp04223.html

你实际上在问两种(至少)不同的情况:

局部变量的Final 方法/类的Final

Jon Skeet已经回答了2)。关于1):

我不认为这有什么区别;对于局部变量,编译器可以推断该变量是否是final变量(只需检查它是否被多次赋值)。因此,如果编译器想要优化只赋值一次的变量,无论变量是否声明为final,它都可以这样做。

Final可能会对protected/public类字段产生影响;在那里,编译器很难发现字段是否被设置了不止一次,因为它可能发生在不同的类中(甚至可能没有被加载)。但即使这样,JVM也可以使用Jon描述的技术(乐观地优化,如果加载了更改字段的类,则恢复)。

总之,我看不出有任何理由它应该有助于性能。 所以这种微观优化不太可能有帮助。您可以尝试对其进行基准测试以确定,但我怀疑它是否会产生影响。

编辑:

实际上,根据Timo Westkämper的回答,final在某些情况下可以提高类字段的性能。我接受纠正。

简单的回答:不用担心!

长一点的回答:

在讨论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对性能有任何可衡量的影响。