我应该声明一个 java 字段“final”吗?如果代码中没有修改,什么时候会发生?
我的问题主要是关于性能。编译器更清楚地知道,例如,某些变量在对象实例化后不会被修改。那么,为什么要费劲去决赛呢?
我认为这里可能有许多结构/逻辑原因,但从性能的角度来看?有关系吗?
谢谢,
My question is mainly about performance. The compiler knows better that, for example, some variable is NOT modified after object instantiation. So, why bother with final?
I presume many structural/logical reasons might come here, but speaking from the performance point of view? Does it matter?
Thanks,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
在现代 JVM 中,final 不应该影响性能。对于私有字段尤其如此,但即使对于非私有字段,JIT 也可以优化非最终字段,因为它们被视为最终字段,然后 取消优化如果它加载了一些实际修改该字段的代码。
也就是说,使用 Final 的主要原因不是性能,而是为了使代码更易于维护。通过将字段设置为最终字段,您可以减少代码读者必须考虑的“移动部分”的数量,从而更容易推理代码。
In a modern JVM, final shouldn't affect performance. This is especially true for private fields, but even for non-private fields the JIT can optimize non-final fields as thought they are final, and then deoptimize if it loads some code that actually does modify the field.
That said, the main reason to use final is not performance, but to make your code more maintainable. By making fields final you are reducing the number of "moving parts" readers of your code have to think about, making it much easier to reason about the code.
对字段使用
final
也会影响线程安全。 Java 内存模型 指出,一旦该对象的构造函数完成,final
字段的值就对所有可以访问该对象的线程可见。这种保证类似于 易失性字段,其中任何线程始终可以看到当前值。对于普通字段则没有这样的保证。而且,正如其他人指出的,JIT 可以对 Final 字段执行积极的优化,这对于普通字段来说并不那么容易,因为任何新加载的类都可以对该字段进行写访问。
Using
final
for a field also has implications for thread safety. The Java Memory Model states that the values offinal
fields becomes visible to all threads that can access the object as soon as the constructor of that object finishes. That guarantee is similar tovolatile
fields, where any thread always sees the current value. There is no such guarantee for normal fields.And, as others noted, the JIT can perform aggressive optimizations for
final
fields, which are not so easy for normal fields, where any newly loaded class could have write accesses to the field.我怀疑从性能的角度来看这是否重要,但如果您(但更可能是其他新开发人员)稍后尝试修改代码中的该字段,这仍然可能是一个好主意。将其标记为
final
甚至会阻止您对其进行编译。I doubt it would matter from a performance point of view, but it still is probably a good idea in case you (but more likely some other new developer) later tries to modify that field in code. Having it marked as
final
will prevent you from even compiling that.final
在编译时用于接受或拒绝源代码是否有效。它不应该有任何运行时影响。final
is used at compile-time to accept or reject your source code as valid. It shouldn't have any run-time implications.如果该字段不是
private
,则 JVM 始终必须做好准备,以便在某个时间加载尚未遇到的类并开始修改它。因此,对于这些字段,显式声明它们final
可能会允许在 JIT 中进行更强的优化。如果 JIT 一次查看一个方法,这对于私有字段来说甚至可能是正确的。另一方面,局部变量上的
final
无法在字节码编译中幸存,因此不会对性能产生影响。If the field is anything but
private
, a JVM will always have to be prepared that a class that it has not encountered yet will at some time be loaded and start modifying it. So for those fields it is possible that explicitly declaring themfinal
will allow stronger optimizations in a JIT. This could even be true for private fields if the JIT is looking at a single method at a time.On the other hand,
final
on local variables does not survive bytecode compilation and so should have no performance effects.对于局部变量,final 修饰符不会保留在字节码中,因此不会有性能差异。对于现场成员来说,绩效影响更为复杂。它可能会向 jit 提示该字段未被修改,并允许其将值缓存在寄存器中。另一方面,final 确实提供了有关字段值对其他线程的可见性的一些保证,这实际上可能会减慢对象构造速度。
就性能而言,我认为这是一种微观优化,其效果很难衡量。
我仍然建议尽可能使用final来向你的同事和未来的自己阐明你的意图。
For local variables the final modifier is not kept in the bytecode, so there can be no performance difference. For a field member the performance implications are more complicated. It might give the jit a hint that the field is not modified and allow it to cache the value in a register. On the other hand, final does give some guarantees regarding the visibility of the fields value to other threads, which might actually slow down object construction.
Performance wise I think this is a micro optimisation whose effect would be hardly measurable.
I would still recommend to use final when possible to clarify your intent to to your colleagues and your future self.
使用
final
并不是对编译器或 JIT 的真正提示。这是对您自己或维护代码的其他开发人员的提示。它清楚地表明类代码的其余部分假设该字段永远不会改变,这可能是一件特别重要的事情(例如,出于正确性和/或线程安全的原因)。它还确保子类不会更改其值(如果该字段受保护)。例如,如果参与其值的所有字段都是最终的,则可以缓存对象的
hashCode
。Using
final
is not really a hint to the compiler or the JIT. It's a hint to yourself, or the other developers maintaining the code. It makes it clear that the rest of the class code assumes that this field never changes, which can be a particularly important thing (for correctness and/or thread-safety reasons, for example). It also makes sure that a subclass may not change its value (if the field isprotected
).The
hashCode
of the object could for example be cached if all the fields participating in its value are final.