如果你在一個函數內創建一個匿名類,並嘗試在靜態類中使用一個參數,那麼javac/IDE會拋出一個錯誤,說你不能在匿名類中使用一個變量除非它被聲明爲最終的......但是由於Java的值傳遞引用了值語義,所有參數都是有效的。那麼爲什麼不在這裏適用相同的語義呢?編譯器的奇怪設計選擇警告
例如錯誤:
public static Optional<Node> getLayerByName(String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
但是,這是罰款:
public static Optional<Node> getLayerByName(final String name) {
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
據我所知,這是唯一的一次,javac命令將迫使你申報的函數參數作爲決賽。關於它是否有權將爭論宣佈爲最終的決定,考慮到由於java的範圍規則而確實是最終結果,所以在這方面存在很多問題。無論如何,它在函數範圍內改變參數引用一般被認爲是不好的做法。
我只是很好奇爲什麼設計選擇強制你聲明它是最終的,就好像它會混淆在這個實例中改變引用內部函數範圍而匿名類使用函數參數,但它不是認爲混淆足以自動聲明所有函數引用爲最終。
編輯 - 這是一個關於Java的語義選擇的問題,而不是爲什麼變量有是最終的問題。
例如對於很多非java背景的程序員而言,可能會期望
public static changeReference(String thing){
thing = "changed";
}
public static void main(String[] args) {
String thing = "orgininal";
changeReference(thing)
System.out.println(thing); //prints original
}
實際上打印「已更改」。從這個意義上說,參數中的所有引用都是最終的,因爲函數內部引用的任何變化都不會影響函數外部的引用。看起來如果我們總是放入final,它會提高清晰度,那麼很明顯changeReference函數不會做任何事情,因爲編譯器會告訴你。但是,如果你允許參數變量的地方rescoping,這真的是比任何如果有更多或更少的困惑:
public static Optional<Node> getLayerByName(String name, Collection<Node> someCollection) {
name = "changed"
Optional<Node> optional = FluentIterable.from(someCollection).firstMatch(new Predicate<Node>() {
@Override
public boolean apply(Node node) {
System.out.println(name);
return name.equals(node.getProperty(LayerProperties.NAME.name()));
}
});
}
public static void main(Collection<Node> someCollection){
getLayerByName("original", someCollection); // prints "original" never "changed"
}
被允許的版畫「原始」,而不是改變了?爲什麼設計者認爲這些行爲中的一個比另一個更容易混淆,並且強加額外的語義來處理它,或者爲什麼他們在這兩個幾乎完全相同的情況下不執行相同的語義?
方法參數不能作出最終的,因爲它會破壞向後兼容性。不幸。 – Kayaman
[爲什麼Java內部類需要「最終」外部實例變量?](http://stackoverflow.com/questions/3910324/why-java-inner-classes-require-final-outer-instance-variables) –
我不認爲這是重複的 - 我知道爲什麼參數*有*是最終的,因爲方法參數在堆棧上,但對象變量在堆上,所以最終保留了只有一個變量的錯覺。問題是,爲什麼他們強迫你在這裏宣佈它,當所有的方法論點都是有效的時候。爲什麼編譯器不能默默使用方法參數。 –