final
只是意味着不能为引用/原始变量分配新值。它与const
概念不同(Java 没有);它不保证不变性。String
当然,在 Java 中,它已经足够不可变了(除非令人讨厌的反射攻击)。
对参数参数使用final
修饰符对安全性或垃圾收集没有影响。这样做是为了可读性并强制执行编码约定,即在方法中不重复使用参数变量来存储其他值。
在遇到final
修饰符时,人类读者可以确信该变量的值一旦分配,将不会在其范围内改变。编译器将强制执行此行为,并且不会编译非法尝试为声明的变量分配新值的程序final
。
可以声明一个变量final
。一个final
变量只能分配一次。如果一个final
变量被赋值给它,这是一个编译时错误,除非它在赋值之前被确定为未赋值。
然而,如上所述,final
它本身并不能保证所引用对象的不变性。final StringBuilder sb
声明保证一旦被分配并在sb
其范围内,将不会引用另一个StringBuilder
实例。StringBuilder
当然,它本身是一个可变对象。
final
和内部类
修饰符的另一个用途final
是允许内部类使用局部变量等:
必须声明任何使用但未在内部类中声明的局部变量、形式方法参数或异常处理程序参数final
。
这与使用这些变量的内部类如何在 Java 中编译有关,实现细节可能与讨论不太相关。本质上,这些final
变量的值在构建时被赋予内部类。内部类实例将看不到对局部变量的后续更改(如果允许)。为了确保正确的语义,必须声明这些局部变量final
。
final
运行时局部变量的修饰符效果
final
局部变量/正式方法参数的修饰符是一个编译时概念,并且不存在于字节码级别(即,它与final
字段、类和方法的修饰符的作用非常不同)。因此,这个概念在运行时根本不存在,其中final
和非final
局部变量是无法区分的;关键字本身的使用不会对垃圾回收性和/或性能产生任何影响。
垃圾可收集性是根据是否存在对对象的实时引用来定义的。局部变量和方法参数在方法末尾(或在其中声明它们的块)超出范围,无论它们是否被声明final
。超出范围意味着引用“已死”。对象本身可能仍然有来自其他地方的实时引用。
在这种特殊情况下,声明了形式方法参数,final
以便它们可以在内部类中使用。如上所述,内部类会复制这些引用以供自己使用。因此,在这种特殊情况下,Authenticator
对象将具有对和引用的String
对象的引用。a
b
简单地说,对对象的引用越多,就越难认定为无法收集的垃圾。然而,根本因素是这些引用的活跃度,而不是它们是否是final
.
在分析
理解这些概念有助于消除对内存使用/性能问题的任何疑虑;最好只分析并查看问题是否真实,并根据需要进行修复。一个设计良好的系统应该高度适应这些变化。