我不知道如何限制你對於內存的使用,但如果你能使用LinkedHashMap
代替HashMap
(LinkedHashMap
使用額外的引用,以保持插入順序),那麼你可以利用它的removeEldestEntry
方法:
public class HackedMap<K, V> extends LinkedHashMap<K, V> {
K lastKey;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
lastKey = eldest.getKey();
return false;
}
K getLastKey() {
return lastKey;
}
}
我認爲這個代碼是不言自明的。我們保留對原始密鑰的參考,我們從removeEldestEntry
方法的論點中獲取。 至於removeEldestEntry
方法的返回值,它是false
,所以我們不允許刪除最老的條目(畢竟,我們不希望該映射工作爲緩存)。
現在,具有共同的插入順序LinkedHashMap
,所述removeEldestEntry
方法被自動通過put
和putAll
稱爲(從removeEldestEntry
方法文檔):
此方法由PUT和的putAll插入一個新的條目之後調用進入地圖。
因此,所有我們現在需要做的就是實現你getExistingKey
方法以這樣一種方式,它調用put
不修改地圖,你可以做如下:
<K, V> K getExistingKey(HackedMap<K, V> map, K k) {
if (k == null) return null;
V v = map.get(k);
if (v == null) return null;
map.put(k, v);
return map.getLastKey();
}
這樣做是因爲,當映射已包含映射到給定鍵的條目時,put
方法將替換該值而不觸摸鍵。
我不知道我做過的空檢查,也許你需要改進。當然這HackedMap
不支持併發訪問,但HashMap
和LinkedHashMap
也不支持。
您可以放心地使用HackedMap
而不是HashMap
。這是測試代碼:
Key k1 = new Key(10, "KEY 1");
Key k2 = new Key(10, "KEY 2");
Key k3 = new Key(10, "KEY 3");
HackedMap<Key, String> myMap = new HackedMap<>();
System.out.println(k1.equals(k2)); // true
System.out.println(k1.equals(k3)); // true
System.out.println(k2.equals(k3)); // true
System.out.println(k1.hashCode() == k2.hashCode()); // true
System.out.println(k1.hashCode() == k3.hashCode()); // true
System.out.println(k2.hashCode() == k3.hashCode()); // true
System.out.println(k1 == k2); // false
System.out.println(k1 == k3); // false
System.out.println(k2 == k3); // false
myMap.put(k1, "k1 value");
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k1 value}
myMap.put(k3, "k3 value"); // Key k1 (the one with its field d='KEY 1') remains in
// the map but value is now 'k3 value' instead of 'k1 value'
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k3 value}
Key existingKey = getExistingKey(myMap, k2);
System.out.println(existingKey == k1); // true
System.out.println(existingKey == k2); // false
System.out.println(existingKey == k3); // false
// Just to be sure
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k3 value}
這裏的Key
類我用:
public class Key {
private final int k;
private final String d;
Key(int k, String d) {
this.k = k;
this.d = d;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key1 = (Key) o;
return k == key1.k;
}
@Override
public int hashCode() {
return Objects.hash(k);
}
@Override
public String toString() {
return "Key{" +
"k=" + k +
", d='" + d + '\'' +
'}';
}
}
這甚至可能嗎? 'k1.equals(k2)// true k1.hashCode()== k2.hashCode()// true k1 == k2 // false' –
當然,這是可能的,絕大多數情況下的對象比較。 'k1 == k2'只有它是同一個對象實例。 –
如果你解釋了這種情況很重要的用例,它可能會有所幫助。 'k2'中是否有其他狀態不構成你需要訪問的'equals()/ hashCode()'的一部分?這種方式打破了這些方法的隱含契約。 –