4

だから、私が理解していることは次のとおりです。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 ですが、同期がないため保証されません。この例ではこれで十分ですが、一般的には悪い習慣です。

4

4 に答える 4

4

変数をオブジェクトと混同しないでください。ローカル変数からの参照は確かにコピーされますが、同じオブジェクト、あなたの場合はマップを参照しています。final配列を含む、この制限を回避するための広く知られているイディオムがあります。

final int[] x = {1};
... use in an anonymous instance...
System.out.println(x[0]);
于 2013-01-25T13:08:54.447 に答える
1

このコメント// Outputs dogは、ほとんどのプラットフォームでほとんどの場合にのみ当てはまるという意味で誤解を招くものです。Map初期スレッドでを更新するのに 1 秒あれば十分ですが、共有データへのアクセスが正しく同期されていない限り、匿名スレッドで更新された値の可視性は保証されません。の関連機能の概要については、メモリの一貫性プロパティを参照してくださいjava.util.concurrent

于 2013-01-25T13:24:26.807 に答える
1

Java does the same thing there as it does with regular method parameters:

Method parameters are passed by reference value, so while you cannot change the object itself, if it is mutable and provides ways of mutating its inner state, you can change that state. You cannot change a string, but you can change the items inside a collection, for example.

The reference is passed by value = the reference is copied. The object itself isn't.

于 2013-01-25T13:06:49.803 に答える
0

Anonymous classes do not get copies of variables, but rather copies of references to the objects, that's why after 1s you get the "right" value which was changed outside the anonymous class.

于 2013-01-25T13:06:45.583 に答える