4

WeakhashMap の概念を理解しています。文字列リテラルと文字列オブジェクトがわかりにくかった。

コードは次のとおりです。

package com.lnt.StringBuf;

import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

public class Test1 {
    public static void main(String[] args) {

        Map w = new WeakHashMap();
        Map h = new HashMap<>();

        String hkey = new String("hashkey");
        String wkey = new String("weakkey");
    /*  String hkey = "hashkey";
        String wkey = "weakkey";*/

        h.put(hkey, 1);
        w.put(wkey, 1);

        System.gc();

        System.out.println("Before");
        System.out.println("hashmap size: " + h.size());
        System.out.println("weakmap size: " + w.size());
        System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
                + "weakmap value: " + w.get("weakkey"));

        hkey = null;
        wkey = null;

        System.gc();
        System.out.println(hkey+" "+wkey);

        System.out.println("After");
        System.out.println("hashmap size: " + h.size());
        System.out.println("weakmap size: " + w.size());
        System.out.println("Hashmap value: " + h.get("hashkey") + "\t"
                + "weakmap value: " + w.get("weakkey"));

        System.out.println(h.entrySet());
        System.out.println(w.entrySet());

    }

}

出力は次のとおりです。

Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 0
Hashmap value: 1    weakmap value: null
[hashkey=1]
[]

ただし、String hkey = new String("hashkey"); の場合。String wkey = new String("weakkey");

を次のコードに置き換えると、出力が変わります。

String hkey = "hashkey";
String wkey = "weakkey";

出力は次のとおりです。

Before
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
null null
After
hashmap size: 1
weakmap size: 1
Hashmap value: 1    weakmap value: 1
[hashkey=1]
[weakkey=1]

質問: 文字列リテラルと文字列オブジェクトを「null」にすることは、WeakHashMap で異なる方法で影響を与えます。理由は何ですか?

4

3 に答える 3

8

文字列リテラルはインターンされます。これは基本的に、主に文字列プールと呼ばれるキャッシュがあることを意味します。そのため、文字列リテラルは常に強く参照されます。そのため、 WeakReferenceand などの弱い構造のキーとして使用するのには適していませんWeakHashMap

自動ボックス化された sについても同じことが言えます。範囲 [-128, 127] の値のオブジェクトのキャッシュintも保持します。したがって、弱い構造のキーにも使用しないでください。IntegerIntegerintint

ただし、エントリを挿入するときに新しいオブジェクトを作成することで、これらの問題を回避できます。たとえば、次の例では、「a」エントリは最終的にマップから削除されますが、「b」エントリは永久にそこに残ります。実際にメモリリークを引き起こします:

WeakHashMap<String, Object> map = new WeakHashMap<>();
map.add(new String("a"), new Object());
map.add("b", new Object());

整数についても同じ例が有効です。

WeakHashMap<Integer, Object> map = new WeakHashMap<>();
map.add(new Integer(56), new Object());
map.add(57, new Object());

ここでは、 のキャッシングのために 57 のエントリがそこに永久に残りますIntegerが、56 のエントリはガベージ コレクタによって削除できます。

キャッシングもBooleanありますが、もちろん2つの値のみです。whereIntegerには 256 個の潜在的に危険な値があり、String事実上、危険な可能性のある無制限の出現があります。それらを作成するには、リテラルを使用する (または を使用するString.intern()) だけで済みます。他にも危険なクラスが存在する可能性があります。

于 2015-02-16T09:17:12.773 に答える
0

文字列をキーとして使用する場合、WeakHashMap には適していません。これは、String オブジェクトが作成されると、JVM が String プールにもオブジェクトを作成するためです。参照を無効にした後でも、文字列プールで強く参照されたままになる場合があります。

Map<String, String> stringWeakHashMap = new WeakHashMap<String, String>();
String str1 = "Key 1";
String str2 = "Key 2";

stringWeakHashMap.put(str1, "Value 1");
stringWeakHashMap.put(str2, "Value 2");
str1 = null;

System.gc();
System.out.println("Weak Hash Map :" + stringWeakHashMap.toString());

上記のコードを実行すると、生成される出力は次のようになります。

弱いハッシュ マップ:{キー 2 = 値 2、キー 1 = 値 1}

于 2015-01-13T14:22:05.307 に答える