2

String在 java 程序中,参数在方法声明中定义。但在方法定义中,它作为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 作为最终变量访问,因为我必须在内部类中使用它。

4

4 回答 4

18

final只是意味着不能为引用/原始变量分配新值。它与const概念不同(Java 没有);它不保证不变性。String当然,在 Java 中,它已经足够不可变了(除非令人讨厌的反射攻击)。

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

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

JLS 14.2.4final变量

可以声明一个变量final。一个final变量只能分配一次。如果一个final变量被赋值给它,这是一个编译时错误,除非它在赋值之前被确定为未赋值。

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


final和内部类

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

JLS 8.1.3 内部类和封闭实例

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

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


final运行时局部变量的修饰符效果

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

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

在这种特殊情况下,声明了形式方法参数,final以便它们可以在内部类中使用。如上所述,内部类会复制这些引用以供自己使用。因此,在这种特殊情况下,Authenticator对象将具有对和引用的String对象的引用。ab

简单地说,对对象的引用越多,就越难认定为无法收集的垃圾。然而,根本因素是这些引用的活跃度,而不是它们是否是final.


在分析

理解这些概念有助于消除对内存使用/性能问题的任何疑虑;最好只分析并查看问题是否真实,并根据需要进行修复。一个设计良好的系统应该高度适应这些变化。

于 2010-06-10T10:34:36.547 回答
3

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

于 2010-06-10T10:34:36.673 回答
0

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

于 2010-06-10T10:35:05.397 回答
0

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

于 2010-06-10T10:35:10.713 回答