Jér*_*nge 9 java iteration null weakhashmap keyset
如果我遍历WeakHashMap的密钥集,我是否需要检查空值?
WeakHashMap<MyObject, WeakReference<MyObject>> hm
    = new WeakHashMap<MyObject, WeakReference<MyObject>>();
for ( MyObject item : hm.keySet() ) {
    if ( item != null ) { // <- Is this test necessary?
        // Do something...
    } 
}
换句话说,当我迭代它们时,是否可以收集WeakHashMap的元素?
编辑
为了这个问题,可以假设null在哈希映射中没有添加任何条目.
我不熟悉WeakHashMap,但你可能有一个空对象.看这个例子:
public static void main(String[] args)
{
    WeakHashMap<Object, WeakReference<Object>> hm
    = new WeakHashMap<Object, WeakReference<Object>>();
    hm.put(null, null);
    for ( Object item : hm.keySet() ) {
        if ( item == null ) { 
          System.out.println("null object exists");  
        } 
    }
}
再次来自WeakHashMap javadoc:
具有弱键的基于哈希表的 Map 实现。当 WeakHashMap 中的某个条目的键不再被日常使用时,该条目将自动被删除。更准确地说,给定键的映射的存在不会阻止该键被垃圾收集器丢弃,即使其可最终化、最终确定,然后回收。当一个键被丢弃时,它的条目实际上会从映射中删除,因此此类的行为与其他 Map 实现有些不同。
我读为:是的...当 WeakHaskMap 中没有对 Key 的剩余外部引用时,那么该 Key 可能会被 GC,从而使关联的 Value 无法访问,因此它(假设没有直接对其的外部引用)有资格获得 GC。
我将测试这个理论。这只是我对 doco 的解释...我没有任何 WeakHashMap 的经验...但我立即看到它作为“内存安全”对象缓存的潜力。
干杯。基思.
编辑:探索 WeakHashMap...专门测试我的理论,即对特定键的外部引用将导致该键被保留...这纯粹是胡说八道;-)
我的测试工具:
package forums;
import java.util.Set;
import java.util.Map;
import java.util.WeakHashMap;
import krc.utilz.Random;
public class WeakCache<K,V> extends WeakHashMap<K,V>
{
  private static final int NUM_ITEMS = 2000;
  private static final Random RANDOM = new Random();
  private static void runTest() {
    Map<String, String> cache = new WeakCache<String, String>();
    String key; // Let's retain a reference to the last key object
    for (int i=0; i<NUM_ITEMS; ++i ) {
      /*String*/ key = RANDOM.nextString();
      cache.put(key, RANDOM.nextString());
    }
    System.out.println("There are " + cache.size() + " items of " + NUM_ITEMS + " in the cache before GC.");
    // try holding a reference to the keys
    Set<String> keys = cache.keySet();
    System.out.println("There are " + keys.size() + " keys");
    // a hint that now would be a good time to run the GC. Note that this
    // does NOT guarantee that the Garbage Collector has actually run, or
    // that it's done anything if it did run!
    System.gc();
    System.out.println("There are " + cache.size() + " items of " + NUM_ITEMS + " remaining after GC");
    System.out.println("There are " + keys.size() + " keys");
  }
  public static void main(String[] args) {
    try {
      for (int i=0; i<20; ++i ) {
        runTest();
        System.out.println();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
一次测试运行的结果(我认为相当令人困惑):
There are 1912 items of 2000 in the cache before GC.
There are 1378 keys
There are 1378 items of 2000 remaining after GC
There are 909 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 1961 items of 2000 remaining after GC
There are 1588 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 1936 items of 2000 remaining after GC
There are 1471 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1669 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1264 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1770 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1679 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1774 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1668 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 1834 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 2000 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 429 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
看起来,当我的代码正在执行时,键仍然消失......在 GC 提示之后可能需要微睡眠......以便给 GC 有时间来做它的事情。无论如何,这种“波动”是有趣的行为。
编辑2:try{Thread.sleep(10);}catch(Exception e){}是的,在 后面直接添加该行System.gc();会使结果“更可预测”。
There are 1571 items of 2000 in the cache before GC.
There are 1359 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
There are 2000 items of 2000 in the cache before GC.
There are 2000 keys
There are 0 items of 2000 remaining after GC
There are 0 keys
.... and so on for 20 runs ...
嗯...当 GC 启动时,缓存就会完全消失...在真实应用程序中的任意时间...没有多大用处...嗯...我想知道 WeakHashMap 的用途是什么?;-)
最后编辑,我保证
这是我的krc/utilz/Random(在上面的测试中使用)
package krc.utilz;
import java.io.Serializable;
import java.nio.charset.Charset;
/**
 * Generates random values. Extends java.util.Random to do all that plus:<ul>
 * <li>generate random values in a given range, and
 * <li>generate Strings of random characters and random length.
 * </ul>
 * <p>
 * Motivation: I wanted to generate random Strings of random length for test 
 *  data in some jUnit tests, and was suprised to find no such ability in the
 *  standard libraries... so I googled it, and came up with Glen McCluskey's
 *  randomstring function at http://www.glenmccl.com/tip_010.htm. Then I thought
 *  aha, that's pretty cool, but if we just extended it a bit, and packaged it
 *  properly then it'd be useful, and reusable. Cool!
 * See: http://www.glenmccl.com/tip_010.htm
 * See: http://forum.java.sun.com/thread.jspa?threadID=5117756&messageID=9406164
 */
public class Random extends java.util.Random  implements Serializable
{
  private static final long serialVersionUID = 34324;
  public static final int DEFAULT_MIN_STRING_LENGTH = 5;
  public static final int DEFAULT_MAX_STRING_LENGTH = 25;
  public Random() {
    super();
  }
  public Random(long seed) {
    super(seed);
  }
  public double nextDouble(double lo, double hi) {
    double n = hi - lo;
    double i = super.nextDouble() % n;
    if (i < 0) i*=-1.0;
    return lo + i;
  }
  /**
   * @returns a random int between lo and hi, inclusive.
   */
  public int nextInt(int lo, int hi) 
    throws IllegalArgumentException
  {
    if(lo >= hi) throw new IllegalArgumentException("lo must be < hi");
    int n = hi - lo + 1;
    int i = super.nextInt() % n;
    if (i < 0) i = -i;
    return lo + i;
  }
  /**
   * @returns a random int between lo and hi (inclusive), but exluding values
   *  between xlo and xhi (inclusive).
   */
  public int nextInt(int lo, int hi, int xlo, int xhi) 
    throws IllegalArgumentException
  {
    if(xlo < lo) throw new IllegalArgumentException("xlo must be >= lo");
    if(xhi > hi) throw new IllegalArgumentException("xhi must be =< hi");
    if(xlo > xhi) throw new IllegalArgumentException("xlo must be >= xhi");
    int i;
    do {
      i = nextInt(lo, hi);
    } while(i>=xlo && i<=xhi);
    return(i);
  }
  /**
   * @returns a string (of between 5 and 25 characters, inclusive) 
   *  consisting of random alpha-characters [a-z]|[A-Z].
   */
  public String nextString()
    throws IllegalArgumentException
  {
    return(nextString(DEFAULT_MIN_STRING_LENGTH, DEFAULT_MAX_STRING_LENGTH));
  }
  /**
   * @returns a String (of between minLen and maxLen chars, inclusive) 
   *  which consists of random alpha-characters. The returned string matches
   *  the regex "[A-Za-z]{$minLen,$maxLan}". 
   * @nb: excludes the chars "[\]^_`" between 'Z' and 'a', ie chars (91..96).
   * @see: http://www.neurophys.wisc.edu/comp/docs/ascii.html
   */
  public String nextString(int minLen, int maxLen)
    throws IllegalArgumentException
  {
    if(minLen < 0) throw new IllegalArgumentException("minLen must be >= 0");
    if(minLen > maxLen) throw new IllegalArgumentException("minLen must be <= maxLen");
    return(nextString(minLen, maxLen, 'A', 'z', '[', '`'));
  }
  /**
   * @does: generates a String (of between minLen and maxLen chars, inclusive) 
   *  which consists of characters between lo and hi, inclusive.
   */
  public String nextString(int minLen, int maxLen, char lo, char hi)
    throws IllegalArgumentException
  {
    if(lo < 0) throw new IllegalArgumentException("lo must be >= 0");
    String retval = null;
    try {
      int n = minLen==maxLen ? maxLen : nextInt(minLen, maxLen);
      byte b[] = new byte[n];
      for (int i=0; i<n; i++)
        b[i] = (byte)nextInt((int)lo, (int)hi);
      retval = new String(b, Charset.defaultCharset().name());
    } catch (Exception e) {
      e.printStackTrace();
    }
    return retval;
  }
  /**
   * @does: generates a String (of between minLen and maxLen chars, inclusive) 
   *  which consists of characters between lo and hi, inclusive, but excluding
   *  character between 
   */
  public String nextString(int minLen, int maxLen, char lo, char hi, char xlo, char xhi) 
    throws IllegalArgumentException
  {
    if(lo < 0) throw new IllegalArgumentException("lo must be >= 0");
    String retval = null;
    try {
      int n = minLen==maxLen ? maxLen : nextInt(minLen, maxLen);
      byte b[] = new byte[n];
      for (int i=0; i<n; i++) {
        b[i] = (byte)nextInt((int)lo, (int)hi, (int)xlo, (int)xhi);
      }
      retval = new String(b, Charset.defaultCharset().name());
    } catch (Exception e) {
      e.printStackTrace();
    }
    return retval;
  }
}
| 归档时间: | 
 | 
| 查看次数: | 2252 次 | 
| 最近记录: |