[英]compact java.util.Map implementation
是否有任何java.util.Map實現不存儲等於ValueObjects的值而僅存儲其中之一? (此對象的引用不同,但是相等)
這是一些測試代碼:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i <= 1000000; i++) {
map.put(i, new Integer(42));
}
和可視VM顯示:這些對象的200萬個Integer實例相等,但Map存儲了所有實例
僅出於歷史記錄的目的,我編碼了chiastic-security的解決方案並對其進行測試以與HashMap進行比較:
public class CompactMap<K, V> implements Map<K, V> {
private Map<K, V> map;
private Map<V, V> canonicalMap;
public CompactMap() {
map = new HashMap<K, V>();
canonicalMap = new HashMap<V, V>();
}
@Override
public void clear() {
map.clear();
canonicalMap.clear();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
return map.entrySet();
}
@Override
public V get(Object key) {
return map.get(key);
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public Set<K> keySet() {
return map.keySet();
}
@Override
public V put(K key, V value) {
V canonValue = canonicalMap.get(value);
V previous = null;
if (canonValue != null) {
previous = map.put(key, canonValue);
} else {
previous = map.put(key, value);
canonicalMap.put(value, value);
}
return previous;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (m == null) throw new NullPointerException("Can't exceute putAll for null-map argument");
for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
}
@Override
public V remove(Object key) {
V removalValue = map.get(key);
map.remove(key);
if (!map.containsValue(removalValue)) {
canonicalMap.remove(removalValue);
}
return removalValue;
}
@Override
public int size() {
return map.size();
}
@Override
public Collection<V> values() {
return map.values();
}
}
測試緊湊圖:
public static void main(String[] args) {
Map<Integer, Integer> compactMap = new CompactMap<Integer, Integer>();
//Map<Integer, Integer> usualMap = new HashMap<Integer, Integer>();
for (int i=0; i<=1000000; i++) {
compactMap.put(i, new Integer(i % 1000));
// usualMap.put(i, new Integer(i % 1000));
}
}
用於CompactMap的VisualVM堆轉儲:
測試HashMap:
public static void main(String[] args) {
// Map<Integer, Integer> compactMap = new CompactMap<Integer, Integer>();
Map<Integer, Integer> usualMap = new HashMap<Integer, Integer>();
for (int i=0; i<=1000000; i++) {
// compactMap.put(i, new Integer(i % 1000));
usualMap.put(i, new Integer(i % 1000));
}
}
HashMap的VisualVM堆轉儲:
標准實現無法解決此問題,但是您可以輕松地自己滾動。 訣竅是保留一個HashMap<K,V> map
來保存您的真實映射,另一個HashMap<V,V> canonical
以確保您的值最終不會包含兩個相等但不同的引用。
每當您想使用map.put(key,value)
向map
添加內容時,都應該
canonical
圖中查找value
,以查看您之前是否遇到過與此相同的事情。 如果canonical.get(value)
返回canonical.get(value)
,則這是您應該放入map
的規范表示形式。 canonical
中不存在它,則調用map.put(key,value)
將其添加到主地圖中,還將canonical.put(value,value)
添加到主地圖中,以便現在可以對與此相等的事物進行規范表示值。 也許您對Java中相等的含義感到困惑。 當您調用new時,將始終創建一個新實例。 確定它是否與另一個相等並不容易,因為它可能具有多個復雜類型的字段。
如果您改為執行以下操作:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Integer answer = new Integer(42);
for (int i = 0; i <= 1000000; i++) {
map.put(i, answer);
}
然后僅創建一個實例。 它將僅指向內存中的一個位置,如果更改,它將更改所有人(盡管Integer和所有其他包裝器在Java中都是不可變的,這意味着不能更改)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.