当final关键字用于方法参数时,我不明白它在哪里真正方便。
如果我们排除匿名类的使用,可读性和意图声明,那么它对我来说几乎毫无价值。
强制某些数据保持不变并不像看上去那么有力。
如果参数是一个原语,那么它将没有任何影响,因为参数是作为值传递给方法的,在作用域之外更改它不会产生任何影响。
如果我们通过引用传递参数,那么引用本身就是一个局部变量,如果从方法内部更改引用,那么从方法作用域外部更改引用不会产生任何影响。
考虑下面的简单测试示例。
这个测试通过了,尽管该方法改变了给它的引用值,但它没有任何影响。
public void testNullify() {
Collection<Integer> c = new ArrayList<Integer>();
nullify(c);
assertNotNull(c);
final Collection<Integer> c1 = c;
assertTrue(c1.equals(c));
change(c);
assertTrue(c1.equals(c));
}
private void change(Collection<Integer> c) {
c = new ArrayList<Integer>();
}
public void nullify(Collection<?> t) {
t = null;
}
跟进米歇尔的帖子。我给自己举了另一个例子来解释。我希望它能有所帮助。
public static void main(String[] args){
MyParam myParam = thisIsWhy(new MyObj());
myParam.setArgNewName();
System.out.println(myParam.showObjName());
}
public static MyParam thisIsWhy(final MyObj obj){
MyParam myParam = new MyParam() {
@Override
public void setArgNewName() {
obj.name = "afterSet";
}
@Override
public String showObjName(){
return obj.name;
}
};
return myParam;
}
public static class MyObj{
String name = "beforeSet";
public MyObj() {
}
}
public abstract static class MyParam{
public abstract void setArgNewName();
public abstract String showObjName();
}
在上面的代码中,在thisIsWhy()方法中,我们实际上并没有将[参数MyObj obj]分配给MyParam中的一个实际引用。相反,我们只是在MyParam的方法中使用[参数MyObj obj]。
但是在我们完成方法thisIsWhy()后,参数(对象)MyObj是否仍然存在?
似乎它应该,因为我们可以看到在main中我们仍然调用方法showObjName(),它需要到达obj。即使方法已经返回,MyParam仍然会使用/到达方法参数!
Java真正实现这一点的方法是在MyParam对象中生成MyObj参数的一个隐藏引用(但它不是MyParam中的一个正式字段,所以我们看不到它)
当我们调用“showObjName”时,它将使用该引用来获得相应的值。
但如果我们没有将参数设为final,这将导致一种情况,我们可以将一个新的内存(对象)重新分配给参数MyObj obj。
从技术上讲,根本没有冲突!如果允许这样做,情况如下:
我们现在在MyParam对象中有一个隐藏的[MyObj obj]指向一个[Memory a in heap]。
我们还有另一个[MyObj obj],它是指向[堆中的内存B]的参数,现在存在于thisIsWhy方法中。
没有冲突,但“令人困惑!!”因为它们都使用了相同的“引用名”,即“obj”。
为了避免这种情况,将其设置为“final”,以避免程序员编写“容易出错”的代码。