有趣的HashMap实现(build 1.7.0_25-b17)

时间:2013-10-04 17:14:28

标签: java android hashmap libgdx

我为Android游戏开发了一个垃圾收集器友好的字符串缓存。它的目的是处理字符串的整数。我犯了一个愚蠢的错误实现它,但这个bug从未在桌面上公开过。然而,在Android中,缓存立即开始返回有趣的字符串:

class IntStringCache {

private final Map<IntStringCache.IntCacheKey, String> cachedStrings = new HashMap<IntStringCache.IntCacheKey, String>();
private final IntCacheKey tempIntCacheKey = new IntCacheKey(0);

public String getStringFor(int i) {
    tempIntCacheKey.setIntValue(i);
    String stringValue = cachedStrings.get(tempIntCacheKey);
    if (stringValue == null) {
        stringValue = String.valueOf(i);
        // ERROR - putting the same object instead of new IntCachKey(i)
        cachedStrings.put(tempIntCacheKey, stringValue);
    }
    return stringValue;
}

public int getSize() {
    return cachedStrings.size();
}

private class IntCacheKey {

    private int intValue;

    private IntCacheKey(int intValue) {
        this.intValue = intValue;
    }

    private void setIntValue(int intValue) {
        this.intValue = intValue;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getOuterType().hashCode();
        result = prime * result + intValue;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        IntCacheKey other = (IntCacheKey) obj;
        if (!getOuterType().equals(other.getOuterType()))
            return false;
        if (intValue != other.intValue)
            return false;
        return true;
    }

    private IntStringCache getOuterType() {
        return IntStringCache.this;
    }

}

所有测试都通过了:

public class IntStringCacheTest {

private IntStringCache intStringCache = new IntStringCache();

@Test
public void shouldCacheString() {
    // given
    int i = 1;

    // when
    String s1 = intStringCache.getStringFor(i);
    String s2 = intStringCache.getStringFor(i);

    // then
    assertThat(s1).isNotNull();
    assertThat(s1).isEqualTo(String.valueOf(i));
    assertThat(s1).isSameAs(s2);
}

@Test
public void shouldCacheTwoValues() {
    // given
    int i1 = 1;
    int i2 = 2;
    int expectedCacheSize = 2;

    // when
    String s1 = intStringCache.getStringFor(i1);
    String s2 = intStringCache.getStringFor(i2);

    // then
    assertThat(intStringCache.getSize()).isEqualTo(expectedCacheSize);
    assertThat(s1).isSameAs(intStringCache.getStringFor(i1));
    assertThat(s2).isSameAs(intStringCache.getStringFor(i2));
}

}

注意:

    assertThat(String.valueOf(1)).isSameAs(String.valueOf(1));

失败。

第二次测试通过的事实很有意思,因为有了这个bug,地图中应该有一个更新的密钥。这可以用hashCode()解释,它可以使相同的键进入HashMap内的两个不同的桶。但是,相同的键(即使在两个桶中)可能会返回相同的两个Stings?似乎即使代码中存在错误,HashMap也能正确完成工作。

另一方面,我的Android Java实现会立即返回错误的数字字符串。

1 个答案:

答案 0 :(得分:2)

您应该考虑将整个类替换为SparseArray或其支持库等效SparseArrayCompat(如果您需要&lt; 3.0设备),因为它们专门用于将整数映射到内存中的对象有效的方式。