Java 方法参数中的final关键字

Java 方法参数中的final关键字,java,final,Java,Final,我经常遇到如下方法: public void foo(final String a, final int[] b, final Object1 c){ } 如果调用此方法而不传递最终参数,会发生什么情况。i、 e.稍后更改的Object1(因此未声明为final)可以传递到此方法,很好Java只是传递值。(或更好-通过值传递引用) 因此,传递的参数和方法中的参数是指向同一对象(值)的两个不同处理程序 因此,如果更改对象的状态,它将反映到引用它的每个其他变量。但是,如果将新对象(值)重新分配给参

我经常遇到如下方法:

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

如果调用此方法而不传递最终参数,会发生什么情况。i、 e.稍后更改的Object1(因此未声明为final)可以传递到此方法,很好

Java只是传递值。(或更好-通过值传递引用)

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


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

Java总是在将参数发送给方法之前复制参数。这意味着final并不意味着调用代码有任何不同。这只意味着在方法内部不能重新分配变量


请注意,如果有最终对象,仍然可以更改对象的属性。这是因为Java中的对象实际上是指向对象的指针。只有指针被复制(并且在方法中是最终的),而不是实际的对象。

考虑foo()的这个实现:


由于
Runnable
实例将比该方法更有效,因此如果没有
final
关键字--
final
将告诉编译器获取引用副本是安全的(稍后再参考)。因此,被认为是最终值的是参考,而不是。换句话说:作为调用者,您不能搞乱任何事情…

字符串是不可变的,因此实际上您不能在之后更改字符串(您只能使保存字符串对象的变量指向不同的字符串对象)

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

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

  a = someObject();
  process(a);

a的字段可能已更改,但a仍然是以前的对象。在通过引用传递的语言中,这可能不是真的。

有一种情况,要求您声明它为final,否则将导致编译错误,即将它们传递到匿名类中。基本示例:

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
修饰符将导致编译错误,因为不再保证该值是运行时常量。从匿名类外部更改值将导致匿名类实例在创建之后表现不同。

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


一些程序员(像我一样)认为这是一件非常好的事情,几乎对每个参数都使用
final
。它使理解长的或复杂的方法变得更容易(尽管有人可能认为长的和复杂的方法应该被重构)。它还将焦点放在没有标记
final

final的方法参数上,这意味着一旦赋值,就不能更改该变量的值

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

如果将任何参数声明为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);  
    }  
}   
输出:编译时错误


有关更多详细信息,请访问我的博客:

不需要方法输入参数中的final关键字。Java创建了对象引用的一个副本,因此在其上加final并不会使对象成为final,而只是使引用成为final,这毫无意义

@Joachim-实际上它与C中的
const
相同!区别在于,在Java中,指向对象的“指针”没有任何特殊的
*
语法。因此,这里出现了混乱。变量是const/final,它指向的对象不是。@Earwicker我想我接受你的观点,但我认为Joachim的说法更准确,他说“final”方法param对调用方没有任何含义,这是真的,但不是“const”的一般含义。顺便说一句,我想你经常会看到这样声明方法的人,他们正确地认为,不将方法参数视为可以更改的局部变量更清晰、更不容易出错final“只是强制执行而已。@Earwicker:我的C很弱。我记得
const
参数迫使传入的每个值也来自
const
变量。看来这是错的。对不起。@Sean:我经常看到它,因为我们的eclipse格式化程序就是这样设置的。这是一个整体概念的产物,它以最受限制的方式(w.r.t访问修饰符和一般)促进编码,因此当您删除限制时,您需要显式地这样做。我的2美分。它当然可以复制(有一种优化,编译器不复制,而复制没有区别)。但是,你必须记住,在对象的情况下。对象实际上只是对对象的引用。因此,在这种情况下,您将获得引用的副本。如果
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);  
    }  
}