方法参数中的final关键字

时间:2010-02-10 12:05:21

标签: java final

我经常会遇到如下所示的方法:

public void foo(final String a, final int[] b, final Object1 c){
}

如果在不传递最终参数的情况下调用此方法会发生什么。即稍后更改的Object1(因此未声明为final)可以很好地传递给此方法

10 个答案:

答案 0 :(得分:163)

Java在将参数发送到方法之前总是复制参数。这意味着最终并不意味着调用代码有任何区别。这仅意味着在方法内部无法重新分配变量。 (请注意,如果您有最终对象,仍可以更改对象的属性。)

答案 1 :(得分:79)

有一种情况,你必需声明它最终 - 否则会导致编译错误 - 即将它们传递给匿名类。基本示例:

public FileFilter createFileExtensionFilter(final String extension) {
    FileFilter fileFilter = new FileFilter() {
        public boolean accept(File pathname) {
            return pathname.getName().endsWith(extension);
        }
    };

    // What would happen when it's allowed to change extension here?
    // extension = "foo";

    return fileFilter;
}

删除final修饰符会导致编译错误,因为不再保证该值是运行时常量。从匿名类外部更改值将导致匿名类实例在创建之后表现不同。

答案 2 :(得分:51)

Java只是按值传递。 (或更好 - 按值传递参考)

因此传递的参数和方法中的参数是指向同一对象(值)的两个不同的处理程序。

因此,如果更改对象的状态,它将反映到引用它的每个其他变量。但是,如果您为参数重新分配新对象(值),则不会重新分配指向此对象(值)的其他变量。

答案 3 :(得分:27)

方法参数上的final关键字对调用者来说绝对没有任何意义。它对运行程序也没有任何意义,因为它的存在或不存在不会改变字节码。它只确保如果在方法中重新分配参数变量,编译器将会抱怨。就这样。但这就够了。

一些程序员(像我一样)认为这是一件非常好的事情,几乎每个参数都使用final。它可以更容易理解一个冗长或复杂的方法(尽管有人可能会认为应该重构长而复杂的方法。)它还突出了标记为{{1}的方法参数。 }}

答案 4 :(得分:17)

考虑foo()的这种实现:

public void foo(final String a) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            System.out.print(a);
        }
    }); 
}

因为Runnable实例比方法更长,所以如果没有final关键字,这将无法编译 - final告诉编译器可以安全地获取引用的副本(稍后再提及)。因此,参考被认为是最终的,而不是。换句话说:作为一个来电者,你不能搞砸任何东西......

答案 5 :(得分:2)

如果您将任何参数声明为final,则无法更改它的值。

class Bike11 {  
    int cube(final int n) {  
        n=n+2;//can't be changed as n is final  
        n*n*n;  
     }  
    public static void main(String args[]) {  
        Bike11 b=new Bike11();  
        b.cube(5);  
    }  
}   

输出:编译时间错误

有关详细信息,请访问我的博客:http://javabyroopam.blogspot.com

答案 6 :(得分:1)

最终表示您无法在分配该变量后更改该值。

同时,对这些方法中的参数使用 final 意味着它不允许程序员在执行方法期间更改其值。 这只意味着在方法内部无法重新分配最终变量。

答案 7 :(得分:0)

字符串是不可变的,因此你不能随后更改字符串(你只能使持有String对象的变量指向不同的String对象)。

但是,这不是您可以将任何变量绑定到final参数的原因。所有编译器检查都是该方法未在 方法中重新分配该参数。这对于文档目的来说是好的,可以说是好的风格,甚至可以帮助优化字节代码以提高速度(尽管这在实践中似乎没有做太多)。

但即使您在方法中重新分配参数,调用者也不会注意到这一点,因为java会按值传递所有参数。序列之后

  a = someObject();
  process(a);

a的字段可能已更改,但a仍然是之前的对象。在传递参考语言中,这可能不是真的。

答案 8 :(得分:0)

@stuXnet,我可以做出完全相反的论点。如果将对象传递给函数,并更改传递的对象的属性,则函数的调用者将在其变量中看到更改的值。这意味着通过引用系统传递,而不是通过值传递。

令人困惑的是在一个系统中传递值或通过引用传递的定义,其中指针的使用对最终用户是完全隐藏的。

Java肯定不会通过值传递,因为这样就意味着可以改变传递的对象并且原始文件不会受到影响。

请注意,您不能改变基元,只能将它们分配给变量。所以测试一个 通过引用或通过使用原语通过值不是一个测试。

在Java中无法用其他语言完成的工作是将调用者的变量重新分配给一个新值,因为Java中没有指针,所以这会让人感到困惑。

答案 9 :(得分:0)

不需要方法输入参数中的final关键字。 Java会创建一个对象引用的副本,因此最终确定对象并不会使对象成为最终对象而只是引用,这是没有意义的