【发布时间】:2011-07-26 08:51:28
【问题描述】:
我已经读过,将某些东西做成最终的,然后在循环中使用它会带来更好的性能,但它对一切都有好处吗?我有很多地方没有循环,但我将 final 添加到局部变量中。它会使其变慢还是仍然很好?
还有一些地方我有一个全局变量 final(例如 android paint),这是否意味着我在循环中使用它时不必将它设为本地 final?
【问题讨论】:
我已经读过,将某些东西做成最终的,然后在循环中使用它会带来更好的性能,但它对一切都有好处吗?我有很多地方没有循环,但我将 final 添加到局部变量中。它会使其变慢还是仍然很好?
还有一些地方我有一个全局变量 final(例如 android paint),这是否意味着我在循环中使用它时不必将它设为本地 final?
【问题讨论】:
您应该考虑的第一件事是;我可以编写此代码的最简单和最清晰的方法是什么。这通常表现良好。
final 局部变量不太可能影响性能。当你有很长的方法时,它们可以帮助你清晰,但我建议分解方法是更好的方法。
final 字段可能会在一定程度上影响性能,但使用final 的更好理由是明确该字段永远不会更改(这也有助于 JIT)
【讨论】:
final 与局部变量上的final 非常不同。在并发编程中,为了实现程序的正确性,将字段设为 final 通常是绝对必要的。
final 但不是,它会行为相同。使它final 清楚地表明原语或引用不会存在线程安全问题,因为它无法更改。注意:引用的对象仍然可以更改。
不要考虑性能。对象成员(字段)上的final 具有重要的内存语义,可以提高性能(但更重要的是,它通常需要使代码完全正常工作)。您应该始终将final 放在对象成员上。然而,对于局部变量,您应该只在它可以提高代码可读性或可以防止维护人员接触您的代码时出现错误的情况下使用它。
Java 社区的普遍共识是每个局部变量上的final 会使代码难以阅读。在性能方面,您可以期望没有优化,因为局部变量很容易为编译器分析。换句话说,编译器可以自己解决。
【讨论】:
根据我的经验,大多数变量都可以声明为final。
但是,它看起来很丑。这是我反对它的主要观点。
如果程序的部分不是性能关键,请注意过早的优化。
【讨论】:
在可能的情况下使用 final 被认为是一种很好的形式(对于字段和变量,而不是类和方法),如果没有其他原因,它会使测试更容易。 Final 永远不会对性能产生负面影响。
【讨论】:
这是我的 2 美分:
在属性上使用 final 以最大程度地减少可变性,并且出于文档目的,仅当局部变量用于内部/匿名类时才对它们使用 final。
不要将其用于微优化!特别是不要在类或方法上使用它们,因为您认为它会提高性能。使类和方法最终禁止继承或覆盖方法。
【讨论】:
Final 属性不应该对性能产生任何影响。除了:在多线程环境中,多个线程访问同一个字段并且“不知道”是否必须重新加载它。局部变量的 final 根本没有影响,因为除了局部范围之外没有任何东西可以访问它们。 Final on 方法可能会在 JIT 编译期间产生影响。如果一个方法是最终的并且很小,编译器可以在循环中内联它,因为很明显没有人会覆盖它。 我通常根本不使用 final 属性,因为 final 属性不能很容易地从 DB 中加载等等。将参数声明给方法 final lokos 丑陋(无论如何我从来没有在我的代码中分配给它们)但可能会防止来自拼写错误的简单错误.然而,如果你开始为你的变量使用正确的名称,你就不会犯这样的错字。
【讨论】:
理论上,如果你将一个局部变量设为final,它就可以被优化。不过,我不认为让它们最终自己真正提高性能,因为优化器可能已经检测到你的本地人什么时候没有改变。话虽如此,帮一点忙也无妨。
在某些情况下,将一个变量变为两个变量会有所帮助,例如从此
String a = "foo";
if (lol) a += "bar";
for(.. 1000 ...) doSomething(a);
到
final String a;
{
String ma = "foo";
if (lol) ma += "bar";
a = ma;
}
for(.. 1000 ...) doSomething(a);
免责声明:我不是 JIT 专家。
【讨论】:
最终变量是常量,因此编译器可以生成常量值而不是变量引用指令。当然,这会提高速度(通常也会提高尺寸)。
还有一些地方我有一个全局变量 final(例如 android paint),这是否意味着我在循环中使用它时不必将它设为本地 final?
对不起,你的意思是你不必:
final int somefinalvalue = 0;
void amethod() {
final int somefinalvalue = 0; // repeated from global one
}
还是什么?请记住,如果您声明与全局变量同名的局部变量,则会“遮蔽”全局变量。即它实际上是一个完全不同的变量。如果您已经拥有全球性的,那就使用它。无需重新声明。
【讨论】:
1 == 1 与 new Object() == new Object() 相反。
正如@perter-lawrey 所说,我认为这不应该是您首先关心的问题。首先,编译器优化可以起到很大的作用;其次,有一些工具可以分析你生成的类文件并做同样的事情,例如ProGuard: java shrinker, optimizer, obfuscator, and preverifier.
【讨论】: