关于Java中的本地最终变量
在java Program中,参数在方法声明中定义为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)} }; }
请帮助我,澄清我的疑虑。 提前致谢
PS我正在访问a和b作为最终变量,因为我必须在内部类中使用它。
final
只是意味着不能为reference / primitive变量赋一个新值。 它与const
概念(Java没有)不同; 它不保证不变性。 当然,Java中的String
已经足够不可变(除非讨厌的reflection攻击)。
对参数参数使用final
修饰符对安全性或垃圾回收没有影响。 这样做是为了提高可读性并强制执行编码约定,即参数变量不会在方法中重复使用以存储其他值。
在遇到final
修饰符时,可以确保人类读者在分配后,该变量的值不会在其范围内发生变化。 编译器会强制执行此行为,并且不会编译非法尝试将新值分配给声明为final
变量的程序。
JLS 14.2.4
final
变量变量可以声明为
final
。final
变量只能分配一次。 如果分配了final
变量,那么编译时错误除非在分配之前明确地未分配。
然而,如上所述, final
本身并不能保证被引用对象的不变性。 final StringBuilder sb
声明保证sb
一旦被赋值并且在其范围内,就不会引用另一个StringBuilder
实例。 当然, StringBuilder
本身是一个可变对象。
final
和内部课程
final
修饰符的另一个用途是允许内部类使用局部变量等:
JLS 8.1.3内部类和封闭实例
使用但未在内部类中声明的任何局部变量,forms方法参数或exception处理程序参数必须声明为
final
。
这与如何使用Java编译使用这些变量的内部类有关,这个实现细节可能与讨论不太相关。 基本上,这些final
变量的值在构造时被赋予内部类。 内部类实例不会看到对局部变量的后续更改(如果允许)。 为了确保正确的语义,必须将这些局部变量声明为final
。
final
修饰符对运行时局部变量的影响
局部变量/forms方法参数的final
修饰符是编译时概念,并且不存在于字节码级别(即,它与字段,类和方法的final
修饰符起着非常不同的作用)。 因此,这个概念在运行时根本不存在,其中final
和非final
局部变量是难以区分的; 关键字本身的使用不会对垃圾收集和/或性能产生任何影响。
垃圾收集性是根据是否存在对象的实时引用来定义的。 无论它们是否被声明为final
,本地变量和方法参数都超出了方法末尾的范围(或者它们被声明的块)。 超出范围意味着参考“死”。 对象本身可能仍然有来自其他地方的实时引用。
在这种特殊情况下,forms化方法参数被声明为final
以便它们可以在内部类中使用。 如上所述,内部类将复制这些引用以供自己使用。 因此,在这种特殊情况下, Authenticator
对象将引用a
和b
引用的String
对象。
简单地说,对一个对象的引用越多,就越难以认定为垃圾难以收集。 然而,潜在因素是这些参考文献的活跃性,而不是它们是否是final
。
关于分析
理解这些概念以清除对内存使用/性能问题的任何疑问是很好的。 最好只是分析并查看问题是否真实,并根据需要进行修复。 精心设计的系统应该能够高度适应这些变化。
不,参数的final
只会影响方法堆栈框架上参数的本地副本。 它不会以任何方式影响或更改作为参数传递的值。
使变量final
与安全性或内存分配无关。 它对安全性或内存使用没有任何影响。
添加final
不会更改签名或创建任何其他问题。 因此,可以在由接口指定的方法中使用(例如)。 它只对方法内部的代码产生影响。