关于Java中的本地最终变量

时间:2010-06-10 10:30:44

标签: java final inner-classes

在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)}
    };
}

请帮助我并澄清我的疑虑。提前致谢

P.S。我正在访问a和b作为最终变量,因为我必须在内部类中使用它。

4 个答案:

答案 0 :(得分:18)

final仅表示无法为引用/原始变量分配新值。它与const概念(Java没有)概念不同;它 NOT 保证不变性。当然,Java中的String已经足够不可变(除非讨厌的反射攻击)。

对参数参数使用final修饰符对安全性或垃圾回收没有影响。这样做是为了提高可读性并强制执行编码约定,即参数变量不会在方法中重复使用以存储其他值。

遇到final修饰符后,可以确保人类读者在分配后,该变量的值不会在其范围内发生变化。编译器会强制执行此行为,并且不会编译非法尝试将新值分配给声明为final的变量的程序。

  

JLS 14.2.4 final Variables

     

变量可以声明为finalfinal变量只能分配一次。如果分配了final变量,那么编译时错误除非在分配之前明确地未分配。

如上所述,final本身并不能保证被引用对象的不变性。 final StringBuilder sb声明保证sb一旦被分配并且在其范围内,将不会引用另一个StringBuilder实例。当然,StringBuilder本身就是一个可变对象。


final和内部类

final修饰符的另一个用途是允许内部类使用局部变量等:

  

JLS 8.1.3 Inner Classes and Enclosing Instances

     

使用但未在内部类中声明的任何局部变量,形式方法参数或异常处理程序参数必须声明为final

这与如何使用Java编译使用这些变量的内部类有关,这个实现细节可能与讨论不太相关。本质上,这些final变量的值在构造时被赋予内部类。内部类实例不会看到对局部变量的后续更改(如果允许)。为了确保正确的语义,必须将这些局部变量声明为final


final修饰符对运行时局部变量的影响

局部变量/形式方法参数的

final修饰符是编译时概念,并且不存在于字节码级别(即它与final修饰符的作用非常不同。领域,类和方法)。因此,这个概念在运行时根本不存在,其中final和非final局部变量无法区分;关键字本身的使用不会对垃圾收集和/或性能产生任何影响。

垃圾收集性是根据是否存在对象的实时引用来定义的。无论是否声明它们final,局部变量和方法参数都超出了方法末尾的范围(或它们声明的块)。超出范围意味着参考“死”。对象本身可能仍然有来自其他地方的实时引用。

在这种特殊情况下,形式化方法参数被声明为final,以便它们可以在内部类中使用。如上所述,内部类将复制这些引用以供自己使用。因此,在这种特殊情况下,Authenticator对象将引用Stringa引用的b个对象。

简单地说,对一个对象的引用越多,就越难以成为垃圾难以收集的垃圾。然而,潜在因素是这些参考文献的活跃度,而不是它们是否为final


关于分析

理解这些概念以清除对内存使用/性能问题的疑虑是很好的;最好只是分析并查看问题是否真实,并根据需要进行修复。精心设计的系统应该能够很好地适应这些变化。

答案 1 :(得分:3)

不,参数上的final仅影响方法堆栈帧上参数的本地副本。它不会以任何方式影响或改变作为参数传递的值。

答案 2 :(得分:0)

添加final不会更改签名或创建任何其他问题。因此,可以在接口(例如)指定的方法中使用。它只对方法内部的代码产生影响。

答案 3 :(得分:0)

使变量final与安全性或内存分配无关。它对安全性或内存使用没有任何影响。