だから、私が理解していることは次のとおりです。Javaはクロージャーをサポートしていないため、変数を包含スコープからネストされたスコープにコピーするため、後で使用できます。これはコピーであるため、オリジナルとコピーを同期する方法はなく、変数は強制的に final に設定されるため、開発者は変数を変更して更新されることを期待できません。この理解は、これらの回答から部分的に得られます
そして、このコードが機能するようになります。
public class SimpleClosure {
public static void main(String[] args) {
new SimpleClosure().doStuff();
}
public void doStuff() {
final int number = 3;
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Integer.toString(number));
}
}.start();
}
}
とても素晴らしい。さて、問題は、 final 修飾子は、変数が指すオブジェクトを変更できないようにするだけですが、問題なくオブジェクトを変更できます。「コピー」が行われた場合、オブジェクトの内容への変更は反映されません。したがって、問題は、次のコードが機能する理由です。
import java.util.HashMap;
import java.util.Map;
public class StretchingClosure {
public static void main(String[] args) {
new StretchingClosure().doStuff();
}
public void doStuff() {
final Map<String, String> map = new HashMap<String, String>();
map.put("animal", "cat");
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(map.get("animal")); // Outputs dog See (1)
}
}.start();
map.put("animal", "dog");
}
}
言うまでもなく、何かが欠けているか、コンパイラがこれらのケースを処理する方法を単純化しすぎています。誰か教えてください。
(1): @trashgod が指摘したように、出力はほとんどのプラットフォームでほとんどの場合 true ですが、同期がないため保証されません。この例ではこれで十分ですが、一般的には悪い習慣です。