我经常遇到如下所示的方法:
public void foo(final String a, final int[] b, final Object1 c){
}
如果在没有传递最终参数的情况下调用此方法会发生什么。即稍后更改的Object1(因此未声明为final)可以很好地传递给此方法
Java 总是在将参数发送到方法之前制作一个副本。这意味着 final 对调用代码没有任何区别。这仅意味着在方法内部不能重新分配变量。
请注意,如果您有最终对象,您仍然可以更改对象的属性。这是因为 Java 中的对象实际上是指向对象的指针。并且只有指针被复制(并且将在您的方法中是最终的),而不是实际的对象。
在某些情况下,您需要将其声明为 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
修饰符会导致编译错误,因为不再保证该值是运行时常量。从匿名类外部更改值将导致匿名类实例在创建之后表现不同。
Java 只是按值传递。(或更好 - 按值传递引用)
因此,传递的参数和方法中的参数是两个不同的处理程序,指向同一个对象(值)。
因此,如果您更改对象的状态,它会反映到引用它的所有其他变量。但是,如果您将新对象(值)重新分配给参数,则指向该对象(值)的其他变量不会被重新分配。
方法参数上的final
关键字对调用者毫无意义。它对正在运行的程序也毫无意义,因为它的存在或不存在不会改变字节码。它仅确保在方法中重新分配参数变量时编译器会抱怨。就这样。但这已经足够了。
一些程序员(比如我)认为这是一件非常好的事情,并且final
几乎可以用于每个参数。它使理解一个长的或复杂的方法变得更容易(尽管有人可能会争辩说应该重构长而复杂的方法。)它还突出了没有标记的方法参数final
。
考虑 foo() 的这个实现:
public void foo(final String a) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.print(a);
}
});
}
因为Runnable
实例的寿命会比方法长,所以如果没有final
关键字, this 将无法编译 --final
告诉编译器获取引用的副本是安全的(稍后引用它)。因此,参考被认为是最终的,而不是value。换句话说:作为呼叫者,你不能搞砸任何事情......
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);
}
}
输出:编译时错误
更多详情请访问我的博客:http: //javabyroopam.blogspot.com
不需要方法输入参数中的 final 关键字。Java 创建了对象引用的副本,因此将 final 放在它上面并不会使对象成为最终对象,而只是引用,这没有意义
字符串是不可变的,因此实际上您不能在之后更改字符串(您只能使保存字符串对象的变量指向不同的字符串对象)。
但是,这不是您可以将任何变量绑定到final
参数的原因。所有编译器检查的是参数没有在方法中重新分配。这有利于文档的目的,可以说是很好的风格,甚至可以帮助优化字节码以提高速度(尽管这在实践中似乎没有多大作用)。
但是,即使您确实在方法中重新分配了参数,调用者也不会注意到这一点,因为 java 会按值传递所有参数。序列后
a = someObject();
process(a);
a 的字段可能已更改,但 a 仍然是以前的对象。在传递引用的语言中,这可能不是真的。