在java程序中,参数在方法声明中定义为String
。但在方法定义中,它作为 final String
变量进行访问。是否会导致一些问题(如安全、内存问题)?
例如:
方法声明
join(String a,String b);
方法定义
public void join(final String a,final String b)
{
Authenticator au = new Authenticator(){
public PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(a,b)}
};
}
请帮我解答一下我的疑惑。提前致谢
附注我将 a 和 b 作为最终变量访问,因为我必须在内部类中使用它。
最佳答案
final
只是意味着不能为引用/原始变量分配新值。它与const
概念不同(Java没有);它不保证不变性。当然,Java 中的 String
已经足够不可变了(除非出现讨厌的反射攻击)。
对参数参数使用final
修饰符不会对安全性或垃圾回收产生影响。这样做是为了提高可读性并强制执行编码约定,即参数变量不会在方法中重用来存储其他值。
在遇到final
修饰符时,人类读者可以放心,该变量的值一旦分配,就不会在其范围内改变。编译器将强制执行此行为,并且不会编译非法尝试为声明为 final
的变量分配新值的程序。
JLS 14.2.4
final
VariablesA variable can be declared
final
. Afinal
variable may only be assigned to once. It is a compile time error if afinal
variable is assigned to unless it is definitely unassigned immediately prior to the assignment.
但是,正如前面提到的,final
本身并不保证所引用的对象的不变性。 final StringBuilder sb
声明保证 sb
一旦被分配并在其范围内,就不会引用另一个 StringBuilder
实例。 StringBuilder
本身当然是一个可变对象。
final
和内部类
final
修饰符的另一个用途是允许内部类使用局部变量等:
JLS 8.1.3 Inner Classes and Enclosing Instances
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared
final
.
这与使用这些变量的内部类在 Java 中的编译方式有关,这个实现细节可能与讨论不太相关。本质上,这些final
变量的值在构造时被赋予内部类。内部类实例将看不到对局部变量的后续更改(如果允许)。为了确保正确的语义,这些局部变量必须声明为 final
。
final
修饰符对运行时局部变量的影响
用于局部变量/形式方法参数的 final
修饰符是一个编译时概念,并且不存在于字节码级别(即,它与 final 起着非常不同的作用)字段、类和方法的
修饰符)。因此,这个概念在运行时根本不存在,其中 final
和非 final
局部变量是无法区分的;关键字本身的使用不会对垃圾回收性和/或性能产生任何影响。
垃圾可收集性是根据是否存在对对象的实时引用来定义的。局部变量和方法参数在方法末尾(或声明它们的 block )超出范围,无论它们是否声明为 final
。超出范围意味着引用“已死”。对象本身可能仍然有来自其他地方的实时引用。
在这种特殊情况下,形式方法参数被声明为final
,以便它们可以在内部类中使用。如上所述,内部类将复制这些引用以供自己使用。因此,在这种特殊情况下,Authenticator
对象将引用 a
和 b
引用的 String
对象>.
简单地说,对对象的引用越多,就越难将其认定为难以收集的垃圾。然而,根本因素是这些引用的活跃度,而不是它们是否最终
。
关于分析
理解这些概念有助于消除对内存使用/性能问题的任何疑问;最好只进行分析并查看问题是否真实,并根据需要进行修复。一个设计良好的系统应该能够高度适应这些变化。
关于java - 关于Java中的局部final变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3013547/