最近、Java オブジェクトによって占有されているメモリを解放する方法を調べていました。その作業中に、Java でオブジェクトがどのようにコピーされるか (浅いコピー/深いコピー)、および使用中のオブジェクトを誤ってクリア/ヌル化することを回避する方法について混乱しました。
次のシナリオを検討してください。
ArrayList<Object>
メソッドに引数として渡します。ArrayList<Object>
スレッドによって処理される実行可能なクラスに渡します。ArrayList<Object>
を に入れるHashMap
。
list = null;
さて、これらのケースで、または を呼び出すとlist.clear();
、オブジェクトはどうなりますか? どちらの場合にオブジェクトが失われ、どちらの場合に参照のみが null に設定されますか?
これはオブジェクトの浅いコピーと深いコピーに関係していると思いますが、Java ではどのような場合に浅いコピーが発生し、どのような場合に深いコピーが発生するのでしょうか?
ベストアンサー1
まず、物体null
nullにすることはできません。この概念は意味がありません。変数ただし、「変数」と「オブジェクト」の概念を非常に慎重に区別する必要があります。区別できれば、質問の答えは自然に出てくるでしょう :)
さて、「浅いコピー」と「深いコピー」についてですが、ここでは「浅いコピー」という用語を避けるほうがよいでしょう。浅いコピーでは、通常、新しいオブジェクトが作成されますが、既存のオブジェクトのフィールドが直接コピーされるだけです。深いコピーでは、それらのフィールドによって参照されるオブジェクトのコピーも取得されます (参照型フィールドの場合)。次のような単純な割り当てです。
ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = list1;
...しないどちらかその意味では、浅いコピーまたは深いコピーです。参照をコピーするだけです。上記のコードの後、list1
と はlist2
独立した変数です。それらは、現時点でたまたま同じ値 (参照) を持っています。どちらかの値を変更しても、もう一方には影響しません。
list1 = null;
System.out.println(list2.size()); // Just prints 0
ここで、変数変数の値が参照するオブジェクトに変更を加えると、その変更は他の変数を通じても表示されます。
list2.add("Foo");
System.out.println(list1.get(0)); // Prints Foo
それで、元の質問に戻りますが、実際のオブジェクトマップ、リスト、配列などに保存するだけです参照オブジェクトは、そのオブジェクトに「ライブ」コードが到達する方法がなくなった場合にのみガベージ コレクションの対象となります。つまり、この場合は次のようになります。
List<String> list = new ArrayList<String>();
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("Foo", list);
list = null;
...オブジェクトを参照するエントリがあるArrayList
ため、オブジェクトはまだガベージ コレクションできません。Map